<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Jaypedia</title>
    <link>https://jaypedia.tistory.com/</link>
    <description>비전공자가 프론트엔드 개발자가 되어 가는 과정을 담은 블로그</description>
    <language>ko</language>
    <pubDate>Wed, 1 Jul 2026 15:53:12 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Millie</managingEditor>
    <image>
      <title>Jaypedia</title>
      <url>https://tistory1.daumcdn.net/tistory/4976594/attach/693fbc0fd37d47239d4af519ea7c12c5</url>
      <link>https://jaypedia.tistory.com</link>
    </image>
    <item>
      <title> 쉬고 싶은 금요일 저녁에 &amp;quot;개발 회고 모임&amp;quot;을 한다고?</title>
      <link>https://jaypedia.tistory.com/385</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vuwnr/btsB3sfjPTP/0PKzrVaX44pd7kLqEajwH1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vuwnr/btsB3sfjPTP/0PKzrVaX44pd7kLqEajwH1/img.jpg&quot; data-alt=&quot;금요일 밤을 이렇게 보낼까? 아니면 회고하면서 보낼까? 선택에 달렸다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vuwnr/btsB3sfjPTP/0PKzrVaX44pd7kLqEajwH1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvuwnr%2FbtsB3sfjPTP%2F0PKzrVaX44pd7kLqEajwH1%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;869&quot; height=&quot;400&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;금요일 밤을 이렇게 보낼까? 아니면 회고하면서 보낼까? 선택에 달렸다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항상 해야겠다고 다짐해놓고 매번 우선순위에서 밀려버리는 주간 회고. 예전에는 쓰는 것이 당연했는데 소홀해지다 보니 어느 새 회고를 쓰지 않는 것이 습관화가 되어 버린 것을 목격했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 회고가 정말 중요하다고 생각한다. 회고를 통해 내가 한 것을 꼼꼼히 적어내려가다 보면, 내가 잘했던 것과 아쉽게 했던 것들이 생각으로만 했을 때보다 훨씬 명확하게 보인다. 잘했던 것은 더 잘해야겠다고 생각하고, 아쉽고 후회가 되는 것들은 자연스레 앞으로 어떻게 개선해야 할지를 생각하게 되어 해결책을 모색하게 된다. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;적지 않으면 내가 뭘 잘했는지, 뭘 못했는지, 앞으로는 어떻게 하는 것이 좋을지를 다 놓치는 것과 같다. 따라서 회고 시간을 놓친다는 것은 발전할 수 있는 기회를 놓치는 것과 같고, 그러면 제자리 걸음 혹은 퇴보의 길을 걷게 된다.&lt;/span&gt; 여기서 굉장한 위기감을 느꼈고, 반드시 예전의 텐션을 되찾아야겠다고 생각했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 어떤 습관을 들일 때, 혼자 할 때보다 같이 할 때 더 시너지가 나고 효율이 좋아지는 것을 경험했다. 그래서 회고 습관을 들이기 위해 회고 스터디를 만들기로 결심했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대상은 나와 비슷한 상황을 겪고 있는 개발자. 주간회고를 꾸준히 쓰고 싶지만, 아직 습관화가 되지 않아서 미루고 있는 사람들.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 날짜를 일부러 &lt;span style=&quot;background-color: #c1bef9;&quot;&gt;금요일&lt;/span&gt;로 정했다. 보통 회고를 일요일에 많이 하는데, 금요일에 하는 이유는 월~금을 되돌아봄과 동시에 주말을 계획하고 그 계획을 다른 사람들에게 선언함으로써 계획을 더 잘 지키도록 하기 위함이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 진행 시간은 1시간으로 정하고, 시간대를 나눠서 낭비가 되는 시간이 없도록 했다. 플랫폼도 Google Meet으로 해서, 3명 이상일 때 1시간 제한이 있기 때문에 시간 관리가 잘 될 거라 생각했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쏟아지듯이 아이디어가 나왔고, 더이상 미룰 수 없었다. 나는 바로 12월 15일부터 시작할 수 있도록 빠르게 모집글을 작성했다. 다음은 내가 작성한 모집글이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;1076&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ku8dK/btsB5ChE02J/2sqLuHS2Pcl5ec4a0bGQ5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ku8dK/btsB5ChE02J/2sqLuHS2Pcl5ec4a0bGQ5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ku8dK/btsB5ChE02J/2sqLuHS2Pcl5ec4a0bGQ5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKu8dK%2FbtsB5ChE02J%2F2sqLuHS2Pcl5ec4a0bGQ5K%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;575&quot; height=&quot;884&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;1076&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자들이 많이 모여 있는 단톡방에도 올려 보고, 개발자 지인 분들에게도 알려 보고 했는데 좀처럼 사람이 모이지 않았다. 아무래도 금요일 저녁이라는 시간 특성상 차분하게 앉아서 회고를 쓴다는 게 쉽지 않을 것이라는 생각이 들었고 게다가 연말이기도 했다. 어느정도 예상은 했지만 마음 한 켠이 아쉬웠다. 요일과 시간을 조정해야 하나 고민할 때쯤 다행히 나를 포함해서 인원 4명이 모두 모였다. 그 때 나는 정말 큰 기쁨을 느꼈고, 참여해 주시는 분들이 너무나 감사했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 첫 모임은 성공적으로 진행했다. 나를 제외한 3분은 모두 백엔드 개발자이시고, 다들 연차가 꽤 있으신 분들이었다. 다들 각자의 자리에서 열심히, 꾸준히 발전을 멈추지 않으려 하는 의지를 가지신 분들이었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회고를 적는 시간이 25분 정도로 길지는 않았기에 나에게는 시간이 좀 빠듯했다. 하지만 집중해서 작성하니 내가 생각한 양보다 훨씬 더 많은 양의 회고를 적을 수 있었다. 회고뿐만 아니라 토요일과 일요일에 어떤 개발 공부를 할지에 대해서도 구체적으로 작성하다 보니 내가 주말 2일을 어떻게 보낼지에 대해서 명확하게 보였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 3번의 회고 모임을 더 진행하면서 더 발전해 나갈 나와 멤버들을 기대해 보기로 했다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;335&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/berd9z/btsB7WMWEYF/IkvGe0nsehIVuCzy6uDxuK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/berd9z/btsB7WMWEYF/IkvGe0nsehIVuCzy6uDxuK/img.jpg&quot; data-alt=&quot;금요일 밤은 차분하게 회고를 쓰는 날.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/berd9z/btsB7WMWEYF/IkvGe0nsehIVuCzy6uDxuK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fberd9z%2FbtsB7WMWEYF%2FIkvGe0nsehIVuCzy6uDxuK%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;670&quot; height=&quot;335&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;335&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;</description>
      <category>What I learned/TIL</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/385</guid>
      <comments>https://jaypedia.tistory.com/385#entry385comment</comments>
      <pubDate>Fri, 15 Dec 2023 23:18:40 +0900</pubDate>
    </item>
    <item>
      <title>프론트엔드 멘토링 2회차 회고</title>
      <link>https://jaypedia.tistory.com/384</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 2주차 멘티 과제&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;JavaScript Deep Dive 1장부터 15장까지 공부해 온 후, 면접 형식으로 질문했을 때 답할 수 있도록 하기&lt;/li&gt;
&lt;li&gt;답변 정답률 체크 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제대로 설명했을 시  &lt;/li&gt;
&lt;li&gt;절반 정도 제대로 설명했을 시  &lt;/li&gt;
&lt;li&gt;틀린 답변 혹은 제대로 설명하지 못했을 시  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 과제 질문들&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;총 59개의 질문 중, 멘티는 10개의 질문을 통과함(정답률 약 17%)
&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;b&gt;다음번엔 정답률이 70% 미만일 경우, 멘토링을 바로 종료하는 것&lt;/b&gt;으로.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. What is Programming?&lt;/h3&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;h3 data-ke-size=&quot;size23&quot;&gt;2. What is JavaScript?&lt;/h3&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;h3 data-ke-size=&quot;size23&quot;&gt;3. JavaScript 개발 환경&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Node.js란 무엇인가?  &lt;/li&gt;
&lt;li&gt;npm이란? (왜 생겼는지 &amp;amp; 왜 유용한지)  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 변수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변수란 무엇인가?  &lt;/li&gt;
&lt;li&gt;변수는 왜 필요한가?  &lt;/li&gt;
&lt;li&gt;식별자란 무엇인가?(변수와 식별자의 차이?)  
&lt;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;자바스크립트 엔진은 변수 선언을 어떻게 수행하는가?  
&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;선언하지 않은 식별자에 접근하면 어떻게 되는가?  &lt;/li&gt;
&lt;li&gt;다음 코드는 어떻게 동작하는가? console.log의 결과는? 그 이유는?  &lt;/li&gt;
&lt;li&gt;console.log(score); var score;&lt;/li&gt;
&lt;li&gt;Garbage collector란 무엇인가?  &lt;/li&gt;
&lt;li&gt;unmanaged language vs. managed language  &lt;/li&gt;
&lt;li&gt;네이밍 컨벤션이란?  
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바스크립트에서는 네이밍 컨벤션을 어떻게 이용하는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 표현식과 문&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값(value)란 무엇인가?  &lt;/li&gt;
&lt;li&gt;literal이란 무엇인가?  &lt;/li&gt;
&lt;li&gt;표현식(expression) vs. 문(statement)의 차이는 무엇인가?  &lt;/li&gt;
&lt;li&gt;token이란?  &lt;/li&gt;
&lt;li&gt;표현식인 문과 표현식이 아닌 문의 차이  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. Data Type&lt;/h3&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;template literal이란?  &lt;/li&gt;
&lt;li&gt;프로그래밍에서 null은 언제 사용하는가?  
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;null과 undefined와 어떻게 다른가?  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;symbol이 무엇인가?  &lt;/li&gt;
&lt;li&gt;데이터 타입이 필요한 이유는 무엇인가?  &lt;/li&gt;
&lt;li&gt;동적 타입 언어와 정적 타입 언어의 차이는?  &lt;/li&gt;
&lt;li&gt;변수를 사용할 때 어떤 점을 주의해야 할까?(데이터 타입과 연관지어서)  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 연산자&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연산자와 피연산자는 무엇인가?  &lt;/li&gt;
&lt;li&gt;이항 산술 연산자와 단항 산술 연산자의 차이는?  &lt;/li&gt;
&lt;li&gt;==와 ===의 차이는?  
&lt;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;h3 data-ke-size=&quot;size23&quot;&gt;8. 제어문&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. 타입 변환과 단축 평가&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;type casting이란 무엇인가?  &lt;/li&gt;
&lt;li&gt;타입 강제 변환(type coercion)이란 무엇인가?  &lt;/li&gt;
&lt;li&gt;?. 연산자와 ?? 연산자는 무엇인가?  &lt;/li&gt;
&lt;li&gt;단축 평가(short-circuit evaluation)이란 무엇인가?  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. 객체 리터럴&lt;/h3&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;h3 data-ke-size=&quot;size23&quot;&gt;11. 원시 값과 객체의 비교  &lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 타입을 원시 타입과 객체 타입으로 구분하는 이유는?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pass by value와 pass by reference의 차이는?&lt;/li&gt;
&lt;li&gt;immutable value란 무슨 뜻인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;immutability란 무엇인가?&lt;/li&gt;
&lt;li&gt;유사 배열 객체란?&lt;/li&gt;
&lt;li&gt;shallow copy vs. deep copy (객체)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12. 함수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 선언문과 표현식의 차이는?  &lt;/li&gt;
&lt;li&gt;화살표 함수는 일반적인 함수와 무엇이 다른가?  &lt;/li&gt;
&lt;li&gt;매개변수는 몇 개까지 만드는 것이 좋을까?  &lt;/li&gt;
&lt;li&gt;함수의 반환문을 생략하면 어떻게 되는가?  &lt;/li&gt;
&lt;li&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;재귀 함수는 무엇인가?  
&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;콜백 함수와 고차 함수는 무엇인가?  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;13. 스코프&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스코프란 무엇인가요?  &lt;/li&gt;
&lt;li&gt;스코프가 왜 유용한가요? 프로그래밍 언어에서 왜 이런 개념이 있을까요?  &lt;/li&gt;
&lt;li&gt;전역 스코프와 지역 스코프의 차이는?  &lt;/li&gt;
&lt;li&gt;스코프 체인  &lt;/li&gt;
&lt;li&gt;렉시컬 환경  &lt;/li&gt;
&lt;li&gt;함수 레벨 스코프와 블록 레벨 스코프의 차이  &lt;/li&gt;
&lt;li&gt;렉시컬 스코프 vs 동적 스코프  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;14. 전역 변수의 문제점  &lt;/h3&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;h3 data-ke-size=&quot;size23&quot;&gt;15. let, const 키워드와 블록 레벨 스코프  &lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;var 키워드로 변수를 선언했을 때 어떤 문제가 있는가?&lt;/li&gt;
&lt;li&gt;함수 레벨 스코프 vs 블록 레벨 스코프 차이&lt;/li&gt;
&lt;li&gt;var와 비교해서 let, const의 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TDZ란 무엇인가? 어떻게 동작하는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;const로 객체를 선언해도 객체의 프로퍼티에 재할당이 가능한 이유는?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 멘티의 질문에 대한 참고 자료&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://poiemaweb.com/js-object-oriented-programming&quot;&gt;https://poiemaweb.com/js-object-oriented-programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://soldonii.tistory.com/78&quot;&gt;https://soldonii.tistory.com/78&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;인터프리터 언어 vs 컴파일 언어
&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://www.youtube.com/watch?v=nrxtQcCLHo4&quot;&gt;https://www.youtube.com/watch?v=nrxtQcCLHo4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.boostcourse.org/cs112&quot;&gt;https://www.boostcourse.org/cs112&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하버드 대학교 CS50 강의인데, 4~6챕터가 기초를 쌓는 데 특히 중요하다 생각해서 추천드렸다. 보니까 나도 중간에 듣다가 만 것이 보인다.(하얀색 동그라미는 아직 수강하지 않은 것) 이것도 시간을 내서 한 번 싹 학습해줘야겠다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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/qLUGM/btssHAzz7iM/BWJhKk0Zqd6MKMYU30p1ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qLUGM/btssHAzz7iM/BWJhKk0Zqd6MKMYU30p1ak/img.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;2551&quot; data-is-animation=&quot;false&quot; style=&quot;width: 34.6%; margin-right: 10px;&quot; data-widthpercent=&quot;35.42&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qLUGM/btssHAzz7iM/BWJhKk0Zqd6MKMYU30p1ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqLUGM%2FbtssHAzz7iM%2FBWJhKk0Zqd6MKMYU30p1ak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;2551&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9rPg5/btssBnuEB5V/quJ106kdzJ6BrPUTZQlxEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9rPg5/btssBnuEB5V/quJ106kdzJ6BrPUTZQlxEK/img.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;2659&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.1947%; margin-right: 10px;&quot; data-widthpercent=&quot;33.99&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9rPg5/btssBnuEB5V/quJ106kdzJ6BrPUTZQlxEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9rPg5%2FbtssBnuEB5V%2FquJ106kdzJ6BrPUTZQlxEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;2659&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PNY3R/btssMEg7Zqb/hsfEHztqqcOwQAUb20hDSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PNY3R/btssMEg7Zqb/hsfEHztqqcOwQAUb20hDSK/img.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;2954&quot; data-is-animation=&quot;false&quot; style=&quot;width: 29.8797%;&quot; data-widthpercent=&quot;30.59&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PNY3R/btssMEg7Zqb/hsfEHztqqcOwQAUb20hDSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPNY3R%2FbtssMEg7Zqb%2FhsfEHztqqcOwQAUb20hDSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;2954&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 다음 주 멘티 과제&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;JavaScript Deep Dive 1~18장 공부해오기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 회고&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JavaScript에 대해서 잘 아는 JavaScript 개발자가 되자&lt;/h3&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;멘티분에게 질문할 질문지를 준비하면서 Deep Dive 책을 다시 한 번 훑어보게 되었고 스스로도 답할 수 있는지 다시 한 번 곱씹게 되었다. 나도 잊어버린 부분이 있었고 그런 부분들을 잘 보충해서 확실하고 선명하게 알아야겠다고 생각했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;학습한 것을 오래도록 내 것으로 남기기 위한 최고의 방법, 멘토링 ✨&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오늘 우연히 &amp;lsquo;&lt;a href=&quot;https://brunch.co.kr/@jihyun-um/48&quot;&gt;공부한 내용을 100% 내 것으로 만드는 방법&lt;/a&gt;&amp;rsquo;이라는 아티클을 보게 되었다. 공부를 분명 열심히 한 것 같은데, 돌아서면 까먹은 적이 하루 이틀이 아니다. 그 이유가 이 글에 나와있는데, 바로 뇌가 기억할 수 있는 저장 공간에는 한계가 있기 때문에 중요한 정보만 남겨 두고 다른 정보는 대뇌에서 망각되기 때문이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NgaEk/btssBpFSsJQ/e8im0lgOzn75EtZek3qd10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NgaEk/btssBpFSsJQ/e8im0lgOzn75EtZek3qd10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NgaEk/btssBpFSsJQ/e8im0lgOzn75EtZek3qd10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNgaEk%2FbtssBpFSsJQ%2Fe8im0lgOzn75EtZek3qd10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1500&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;William Glasser라는 미국의 정신과 의사는 위와 같은 학습 방법에 따른 기억률을 제시했다. 읽고, 듣고, 보는 방법으로 공부했을 때는 많아봤자 30%라는 저조한 수치만 기억되는 것을 볼 수 있다.&lt;/li&gt;
&lt;li&gt;반면 남들과 토론했을 때, 직접 내가 경험했을 때, 다른 사람을 가르쳤을 때와 같이 보다 능동적인 방식으로 학습을 했을 때는 기억률이 95%까지 높게 올라가는 것을 볼 수 있다. 이것을 보고, 내가 지금 진행하는 멘토링이 정말 오래 기억에 남기기에 좋은 방식이라는 것을 다시 한 번 느낄 수 있었다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Mentoring</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/384</guid>
      <comments>https://jaypedia.tistory.com/384#entry384comment</comments>
      <pubDate>Thu, 31 Aug 2023 16:48:25 +0900</pubDate>
    </item>
    <item>
      <title>프론트엔드 멘토링 2기를 시작하며</title>
      <link>https://jaypedia.tistory.com/383</link>
      <description>&lt;h1&gt;&lt;b&gt;0. Introduction&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시작하게 된 계기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfiirC/btsr5L9xkWs/yZqfk2MAkGwXi4arkKdbv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfiirC/btsr5L9xkWs/yZqfk2MAkGwXi4arkKdbv0/img.png&quot; data-alt=&quot;프론트엔드 멘토링 1기의 기록들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfiirC/btsr5L9xkWs/yZqfk2MAkGwXi4arkKdbv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfiirC%2Fbtsr5L9xkWs%2FyZqfk2MAkGwXi4arkKdbv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1382&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1382&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프론트엔드 멘토링 1기의 기록들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2022년 10월 17일부터 2023년 7월 23일까지, 거의 9개월 가량 진행된 멘토링이 막을 내리게 되었다. 함께 하던 멘티분은 진로를 프론트엔드 개발자가 아닌 본업으로 돌아가고자 하셨고, 코딩은 취미 쪽으로 돌리고자 하셨다. 정말 열정적으로 참여해주시고, 질문도 잘 해주시고, 회고도 정성스럽게 남겨주셨는데 아쉬웠지만 종료를 해야만 했다.&lt;/li&gt;
&lt;li&gt;나는 새로운 멘티를 찾고 싶었다. 누군가를 가르치기 위해서 준비하는 과정에서 공부가 많이 필요하고, 설명하면서 개념이 선명해진다. 이렇게 공부했을 때 가장 오래 남는다는 것을 알고, 또 무엇보다도 혼자 공부하는 것보다 같이 공부할 때 더 시너지가 나고 재미도 있다. 또한 내가 다른 사람을 도울 수 있다는 효능감도 얻을 수 있다.&lt;/li&gt;
&lt;li&gt;내가 기획한 오프라인 면접 스터디에 참여하신 연지님에게 멘토링 제안을 드렸다. 연지님은 프론트엔드 개발자로 3년간의 경력이 있지만, JavaScript ES5 문법으로 jQuery를 사용하셨기에 JavaScript의 동작 원리나 React를 배우고 싶어하셨다. 연지님은 내가 과거에 진행했던 멘토링에 대해서 들으시고 흔쾌히 멘토링에 참석하고 싶으시다는 의사를 밝히셨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목표&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8월 21일 월요일 오전 9시, 본격적인 멘토링 전에 멘토링의 일정과 목표, 규칙을 정하는 시간을 가졌다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;핵심 목표는 &lt;b&gt;JavaScript의 동작 원리와 문법 대해서 제대로 이해하고 활용할 줄 아는 프론트엔드 개발자가 되는 것&lt;/b&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;JavaScript Deep Dive 책을 처음부터 끝까지 정독하며 자바스크립트에 대한 개념을 확고하게 다질 것이다.&lt;/li&gt;
&lt;li&gt;JavaScript로 직접 Web Application을 구축해 보며 숙련도도 높여볼 것이다.&lt;/li&gt;
&lt;/ul&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;멘토링은 7주(8/24~10/5)간 매주 목요일 2시간 오프라인으로 만나서 진행함&lt;/li&gt;
&lt;li&gt;매주 멘티에게는 과제가 주어짐&lt;/li&gt;
&lt;li&gt;약 1시간은 과제 리뷰, 1시간은 멘티가 준비한 수업으로 진행&lt;/li&gt;
&lt;li&gt;멘토링 후 멘토와 멘티 모두 회고를 블로그에 남기기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;1. 과제 리뷰&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1주차 멘티 과제&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://junilhwang.github.io/TIL/Javascript/Design/Vanilla-JS-Component/&quot;&gt;Vanilla JavaScript로 웹 컴포넌트 만들기&lt;/a&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://roeb.tistory.com/1&quot;&gt;멘티가 정리한 블로그 글&lt;/a&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;멘티분은 아직 JavaScript의 기본 문법에 대해서 잘 모르시는 부분이 많아서, 코드를 이해하시는 데 어려움을 겪고 계셨다. 웹 컴포넌트를 만드는 것이 아직 멘티분에게 어려운 과제였고, 기초적인 문법부터 짚고 넘어가는 시간을 가졌다.&lt;/li&gt;
&lt;li&gt;오늘은 아래와 같은 JavaScript 개념에 대해 설명드렸다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이벤트 버블링 &amp;amp; 이벤트 위임&lt;/li&gt;
&lt;li&gt;this, this binding&lt;/li&gt;
&lt;li&gt;module (export, import)&lt;/li&gt;
&lt;li&gt;생성자 함수&lt;/li&gt;
&lt;li&gt;class&lt;/li&gt;
&lt;li&gt;식별자&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;2. 오늘의 수업: JavaScript 큰 틀에서 보기&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;An Introduction to JavaScript&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 문법을 파헤쳐보기 전, 이 언어에 대해 알아보자! JavaScript로는 무엇을 할 수 있으며, 다른 기술들은 JS를 어떻게 활용하고 있을까?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바스크립트는 태초에 무엇을 위해 만들어진 언어일까?
&lt;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;정말 빠르게 만들어졌다. 1995년, 단 10일 만에 만들어졌다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;script란 무엇일까?
&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;script는 웹 페이지의 HTML 안에 작성할 수 있다.&lt;/li&gt;
&lt;li&gt;script는 웹 페이지를 불러올 때 자동으로 실행된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉, &lt;b&gt;특별한 준비나 컴파일 없이&lt;/b&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;a href=&quot;https://www.oowgnoj.dev/review/advanced-js-1&quot;&gt;이 블로그&lt;/a&gt;를 참고해보자.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;compile이 무엇일까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터는 0과 1로 된 명령을 이해할 수 있고, 실행한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A라는 문자를 입력하더라도 컴퓨터는 이것을 0, 1로 이루어진 이진 코드로 해석한다.&lt;/li&gt;
&lt;li&gt;이 A라는 문자를 해석하는 것이 바로 컴파일러이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정리하자면 &lt;b&gt;사람이 이해하는 언어를 컴퓨터가 이해할 수 있는 언어로 바꿔주는 것&lt;/b&gt;이 컴파일이다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://m.blog.naver.com/PostView.nhn?blogId=white_cap&amp;amp;logNo=221003190571&amp;amp;proxyReferer=https:%2F%2Fwww.google.com%2F&quot;&gt;참고 블로그&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;왜 이름이 JavaScript일까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음 자바스크립트가 만들어졌을 때는 LiveScript였다.&lt;/li&gt;
&lt;li&gt;그런데 당시에 Java 언어의 인기가 좋았다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JavaScript를 Java의 동생 격으로 홍보하면 잘 홍보되겠지?라는 생각&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하지만 언어 자체는 정말 다르다. 아무런 연관이 없다.&lt;/li&gt;
&lt;li&gt;JavaScript는 꾸준히 발전하며 ECMAScript라는 고유한 명세를 갖춘 독립적인 언어가 되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JavaScript는 어디에서 실행할 수 있을까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Browser
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;JavaScript virtual machine&lt;/b&gt;이라는 엔진이 내장되어 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Server
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JavaScript engine&lt;/b&gt;이 들어 있는 모든 디바이스
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;V8 - Chrome, Opera에서 쓰임&lt;/li&gt;
&lt;li&gt;SpiderMonkey - Firefox에서 쓰임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JavaScript Enigne은 어떻게 동작할까? (간단히)
&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;엔진이 script를 읽는다.(parsing)&lt;/li&gt;
&lt;li&gt;읽어 들인 script를 기계어로 전환한다.(compile)&lt;/li&gt;
&lt;li&gt;기계어로 전환된 코드가 실행된다. 기계어로 전환되었기 때문에 실행 속도가 빠르다.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔진은 프로세스 각 단계마다 &lt;b&gt;최적화&lt;/b&gt;를 진행한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;심지어 컴파일이 끝나고 &lt;b&gt;실행 중인 코드를 감시&lt;/b&gt;하면서, 이 코드로 흘러가는 &lt;b&gt;데이터를 분석&lt;/b&gt;하고, 분석 결과를 토대로 &lt;b&gt;기계어로 전환된 코드를 다시 최적화&lt;/b&gt;하기도 한다.&lt;/li&gt;
&lt;li&gt;이런 과정을 거치면 스크립트 실행 속도는 더 빨라진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Can &amp;amp; Can&amp;rsquo;t&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;What can in-browser JavaScript do?&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Modern JavaScript is a &amp;ldquo;&lt;b&gt;safe&lt;/b&gt;&amp;rdquo; programming language.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바스크립트는 왜 &lt;b&gt;안전한&lt;/b&gt; 프로그래밍 언어라고 할까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리, CPU 같은 저수준 영역의 조작을 허용하지 않기 때문이다.&lt;/li&gt;
&lt;li&gt;애초에 이런 접근이 필요하지 않은 브라우저를 대상으로 만든 언어이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JavaScript로 할 수 있는 것은 실행 환경에 따라 다르다.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Browser 환경
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 페이지 조작
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지에 새로운 HTML 추가하기&lt;/li&gt;
&lt;li&gt;기존 HTML이나 스타일 수정하기&lt;/li&gt;
&lt;li&gt;마우스 클릭, 포인터 움직임, 키보드 눌림과 같은 사용자 행동에 반응하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;클라이언트, 서버의 상호작용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크를 통해 원격 서버에 요청을 보내거나 파일 다운로드, 업로드하기 (AJAX, COMET과 같은 기술 사용)&lt;/li&gt;
&lt;li&gt;쿠키 가져오기, 설정하기, 사용자에게 질문을 건네거나 메시지 보여주기&lt;/li&gt;
&lt;li&gt;클라이언트 측에 데이터 저장하기(Local Storage)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Node.js 환경
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일을 읽거나 쓰기&lt;/li&gt;
&lt;li&gt;네트워크 요청을 수행하는 함수 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;What CAN&amp;rsquo;T in-browser JavaScript do?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/li&gt;
&lt;li&gt;웹 페이지 내의 script는 디스크에 저장된 파일을 읽거나 쓰고 복사하거나 실행 시 제약 받을 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;운영체제가 지원하는 기능을 브라우저가 직접 쓰지 못하게&lt;/b&gt; 막혀 있기 때문&lt;/li&gt;
&lt;li&gt;모던 브라우저를 사용하면 파일을 다룰 수는 있지만, 접근은 제한되어 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 브라우저 창에 파일을 끌어다 두거나, &amp;lt;input&amp;gt; 태그에서 파일을 선택할 때와 같이 특정 상황에서만 파일 접근을 허용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;카메라, 마이크같은 디바이스와 상호작용하려면 사용자가 명시적으로 허가해야만 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JavaScript가 활성화된 페이지에서 사용자 몰래 웹캠을 작동시켜 수집한 정보를 국가안보국(NSA)과 같은 곳에 몰래 전송하는 것을 막기 위해서이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;브라우저 내의 탭, 창은 서로의 정보를 알 수 없다. (대부분)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JavaScript를 사용해서 하나의 창에서 다른 창을 열 때에는 예외가 적용된다. 하지만 이 경우에도 &lt;b&gt;도메인, 프로토콜, 포트&lt;/b&gt;가 다르다면 페이지에 접근할 수 없다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러한 제약사항을 동일 출처 정책(Same Origin Policy)라고 한다. 이 정책을 피하려면 두 페이지는 데이터 교환에 동의해야 하고, 동의와 관련된 특수한 자바스크립트 코드를 포함하고 있어야 한다. 이 정책 역시 사용자의 보안을 위해서 만들어 진 것이다. &lt;a href=&quot;http://anysite.com&quot;&gt;http://anysite.com&lt;/a&gt;에서 받아온 페이지가 &lt;a href=&quot;http://gmail.com&quot;&gt;http://gmail.com&lt;/a&gt;에서 받아온 페이지 상의 정보에 접근해 중요한 개인정보를 훔치는 걸 막기 위함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;자바스크립트를 이용하면 &lt;b&gt;페이지를 생성한 서버&lt;/b&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;가능하려면 원격 서버에서 명확히 승인을 해 줘야 한다(HTTP Header등을 이용해서) - 이것 역시 보안을 위한 것.&lt;/li&gt;
&lt;li&gt;브라우저 환경이 아닌 서버라면 이러한 제약은 없다.&lt;/li&gt;
&lt;li&gt;모던 브라우저에서는 추가 권한 허가를 요청하는 플러그인이나 익스텐션 설치가 허용된다.&lt;img src=&quot;https://s3-us-west-2.amazonaws.com/secure.notion-static.com/bb5b3e8d-3ccd-4b54-bcf8-4811afd4fbb0/Untitled.png&quot; alt=&quot;&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;What makes JavaScript unique?&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;There are at least three great things about JavaScript:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Full integration with HTML/CSS.&lt;/li&gt;
&lt;li&gt;Simple things are done simply.&lt;/li&gt;
&lt;li&gt;Supported by all major browsers and enabled by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 세 가지를 모두 지원하는 브라우저 연관 기술은 JavaScript 뿐! 이러한 특징 때문에 자바스크립트는 브라우저 인터페이스를 만들 때 가장 널리 사용되고 있다. 이외에도 서버, 모바일앱을 만드는 것도 가능하다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Languages &amp;ldquo;over&amp;rdquo; JavaScript&lt;/h3&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바스크립트의 문법(syntax)가 어떤 이들에게는 맞지 않을 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트마다 요구사항이 달라서 당연함. 어떤 프로젝트에는 JS가 아닌 다른 언어가 더 찰떡일 수 있다&lt;/li&gt;
&lt;li&gt;그래서 최근에 새로운 언어가 좀 많이 등장했는데 이런것들은 브라우저에서 실행되기 전에 JavaScript로 트랜스파일(transpile, convert) 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;최신 툴을 사용하면 이 트랜스파일을 빠르게 진행할 수 있다. 개발자는 자바스크립트가 아닌 다른 언어로 코딩하고, 이것이 자바스크립트로 자동 변환(auto-converting) 되는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Examples of such languages:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CoffeeScript
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Syntactic sugar for JavaScript&lt;/li&gt;
&lt;li&gt;It introduces shorter syntax, allowing us to write clearer and more precise code.&lt;/li&gt;
&lt;li&gt;Usually, Ruby devs like it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TypeScript
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strict data typing(자료형 명시하기)&lt;/li&gt;
&lt;li&gt;developed by Microsoft&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Flow
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;also adds data typing but in a different way&lt;/li&gt;
&lt;li&gt;developed by Facebook&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dart
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;a standalone language that has its own engine that runs in non-browser environments (like mobile apps), but also can be transpiled to JavaScript.&lt;/li&gt;
&lt;li&gt;Developed by Google.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Brython
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;a Python transpiler&lt;/b&gt; to JavaScript that enables the writing of applications in pure Python without JavaScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kotlin
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;a modern, concise and safe programming language that can target the browser or Node.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;There are more.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Of course, even if we use one of these transpiled languages, we should also know JavaScript &lt;b&gt;to really understand what we&amp;rsquo;re doing&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reference: &lt;a href=&quot;https://javascript.info/intro&quot;&gt;https://javascript.info/intro&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;3. 필수 참고 자료&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wormwlrm.github.io/2020/08/12/History-of-JavaScript-Modules-and-Bundlers.html&quot;&gt;JavaScript 번들러로 본 조선시대 붕당의 이해 - 재그지그의 개발 블로그&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/import-export&quot;&gt;모듈 내보내고 가져오기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.howdy-mj.me/general/history-of-web&quot;&gt;웹 브라우저의 역사&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;4. 다음 주 멘티 과제&lt;/b&gt;&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JavaScript Deep Dive 1장부터 15장까지 정독하고 공부 후 테스트
&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;테스트 문항은 멘토가 만들고, 면접 형식으로 물어볼 예정&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;5. 회고&lt;/b&gt;&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저번 멘토링은 100% 온라인으로 진행했었는데, 이번 멘토링은 오프라인으로 진행하니 새로운 느낌이 났다. 확실히 더 생생하고, 전달력도 더 좋아진다는 생각이 들었다.&lt;/li&gt;
&lt;li&gt;내가 알고 있다고 생각하는 것도 다른 사람에게 설명을 하려고 하면 막상 막히는 경우가 많다. JavaScript의 this에 대해서는 알고 있었지만, this binding에 대해서 구체적으로 설명하려니 막혀서 책을 참고해야 했다. 이 과정에서 바인딩의 의미도 복습할 수 있었다.(바인딩은 식별자와 값을 연결하는 과정, 변수를 선언하는 것은 변수의 이름, 즉 식별자와 확보된 메모리 공간의 주소를 바인딩하는 것. this 바인딩은 this와 this가 가리킬 객체를 바인딩하는 것! 이것도 나중에 한 번 제대로 정리를 해야겠다.)
&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;또 평소에 JavaScript의 동작 원리에 대해서 말하는 기회가 많지 않기 때문일 수도 있다. 언급이 많이 되지 않다 보니 점점 잊혀지게 되고, 그러다보면 설명하기도 어려워진다.&lt;/li&gt;
&lt;li&gt;개발에 관해서 계속 이야기할 수 있는 자리를 더 마련하고, 활발하게 이야기해야겠다고 느꼈다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;멘토링이 끝나는 7주 후에 지금의 나를 돌아봤을 때, &amp;lsquo;와 정말 성장했다&amp;rsquo;라는 생각이 들 수 있을 정도로 좋은 멘토링이 되었으면 좋겠다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Mentoring</category>
      <category>멘토링</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/383</guid>
      <comments>https://jaypedia.tistory.com/383#entry383comment</comments>
      <pubDate>Thu, 24 Aug 2023 16:31:52 +0900</pubDate>
    </item>
    <item>
      <title>(약간은 험난했던) Next.js 13에 MSW 도입기</title>
      <link>https://jaypedia.tistory.com/382</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. MSW 도입 배경&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js 13버전으로 진행 중인 프로젝트에 MSW를 도입하고 싶다는 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 다른 React 프로젝트에서 MSW를 도입해 유용하게 활용한 적이 있다. 백엔드 팀원들과 함께 API 스펙에 대해서 논의가 끝났는데 아직 구현이 덜 되어 API를 프론트 측에서 사용할 수 없는 상황이라면, 마냥 기다리기엔 시간이 아깝다. 바로 이 때 API를 Mocking한다면, 프론트에서도 기능/UI 구현 작업을 이어나갈 수 있다. 추후 API가 개발된다면, 자연스럽게 실제 API로 대체하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또현 현재 나의 프로젝트에는 OAuth 로그인을 도입한 상태다. 로그인 후에는 서버로부터 쿠키를 통해 access token이 발급되는데, 추후 API 요청을 할 때 이 access token을 함께 Request Header에 실어서 보내야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 개발 환경인 localhost:3000 에서는 실제 도메인과 다르기 때문에, access token을 받을 수가 없다. 그렇기 때문에 추후 API 요청에서도 access token을 실어서 보낼 수가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 이러한 API 요청이 포함된 컴포넌트를 개발할 때마다, Next.js 앱을 실제 도메인에 배포해서 구현이 잘 되었는지 확인을 해야 한다는 것인데, 이는 다음과 같은 문제점이 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이 방식은 번거롭기도 하고, 결과물을 확인하기까지 시간이 소요된다. 커밋을 하고, 푸시를 하고, 빌드를 기다려야 하는데 최소 2분에서 길면 3~4분까지 소요가 된다.&lt;/li&gt;
&lt;li&gt;막상 결과물을 확인했더니 로컬에서 확인하지 못했던 에러가 발생하는 경우가 있다. 이럴 경우에는 커밋을 reset해서 다시 과거 상태로 돌리고 작업을 하게 되는데 이는 굉장히 비효율적이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 불편함과 비효율을 없애 로컬 작업 환경을 쾌적하게 만들기 위해 MSW를 도입하고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 Next.js 13 버전, 그리고 app router를 쓰는 환경에서는 MSW를 도입하는 것이 약간 난관이었는데, 내가 마주한 문제점과 해결책을 정리해 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하는 데 일등 공인은 코드스쿼드 부트캠프의 같은 기수 수료생인 콜라이다. 콜라는 이미 다른 프로젝트에서 이 문제를 해결해 본 경험이 있었고, 나에게 아주 자세하고 친절하게 설명해 주셔서 정말 감사했다.(감사의 의미로 기프티콘을 보내드렸다☕️) 콜라와 이야기를 나누는 과정에서 배운 것이 많아 휘발되지 않도록 그 과정을 정리하고 기록해 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. MSW의 동작 방식&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 MSW를 설정하기 전, MSW가 무엇이고 어떤 방식으로 동작하는지 간략하게만 짚고 넘어가보자.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MSW는 무엇이고, 하는 주된 일은 무엇인가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MSW는 Mock Service Worker. Mock은 &amp;lsquo;모의&amp;rsquo;, &amp;lsquo;모조&amp;rsquo;, &amp;lsquo;가짜&amp;rsquo; 라는 뜻이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름 안에 Service Worker가 있는 것처럼, Web에서 제공하는 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API&quot;&gt;Service Worker API&lt;/a&gt;를 사용해서 HTTP 요청을 가로챈다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Service Worker&lt;/b&gt;: 웹 애플리케이션의 메인 스레드와 분리된 별도의 백그라운드 스레드에서 실행시킬 수 있는 기술. 이를 통해 애플리케이션의 UI Block 없이 연산 처리를 할 수 있다. Service Worker를 통해 네트워크 요청이나 응답을 가로채 조작할 수 있게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MSW는 실제 API 요청이 발생하면, 이 요청을 가로채서 미리 준비해 뒀던 Mock data로 응답해준다.&lt;/li&gt;
&lt;li&gt;MSW를 사용하면 Mock Server를 따로 구축하지 않아도 API를 Mocking할 수 있어서 효율성이 증대된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Mock Service Worker의 request 흐름&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 도식은 Mock Service Worker의 request가 어떤 식으로 흘러가는지 큰 그림으로 표현한 것이다. &lt;a href=&quot;https://mswjs.io/docs/&quot;&gt;공식문서&lt;/a&gt;를 참조했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;744&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U7P0i/btsrEq5UION/bLa6NhM8FOkKzczhF2gTu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U7P0i/btsrEq5UION/bLa6NhM8FOkKzczhF2gTu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U7P0i/btsrEq5UION/bLa6NhM8FOkKzczhF2gTu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU7P0i%2FbtsrEq5UION%2FbLa6NhM8FOkKzczhF2gTu1%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;744&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;744&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;브라우저에서 요청을 보낸다.&lt;/li&gt;
&lt;li&gt;Service Worker는 요청을 받고, 해당 요청을 복제한다. 복제한 요청을 MSW에게 보낸다.&lt;/li&gt;
&lt;li&gt;MSW는 요청과 일치하는 목업을 생성한다.&lt;/li&gt;
&lt;li&gt;MSW가 모킹한 응답을 Service Worker에게 보낸다.&lt;/li&gt;
&lt;li&gt;Service Worker가 모킹된 응답을 브라우저에게 보내고, 브라우저가 최종적으로 이 응답을 받는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. MSW 세팅 과정&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MSW가 어떤 흐름으로 Mocking을 해 주는 것인지 파악했으니, 이제 본격적으로 프로젝트에 세팅을 할 차례다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고: &lt;a href=&quot;https://mswjs.io/docs/getting-started/integrate/browser&quot;&gt;https://mswjs.io/docs/getting-started/integrate/browser&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;MSW를 설치하고, public 폴더에 mockServiceWorker 파일을 생성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1692593975773&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// install MSW
npm install msw --save-dev

// create mockServiceWorker file in public folder 
npx msw init public/ --save&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&amp;nbsp;Handler 함수들을 만들어서 API를 모킹한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;REST API 방식, GraphQL API 방식 중에 선택해서 API를 모킹할 수 있다.&lt;/li&gt;
&lt;li&gt;나는 REST API 방식이어서 msw에서 rest를 import한 후 사용했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// src/mocks/checklist/handler.ts
import { rest } from 'msw';

import { API_PATH } from '@/constants/paths/apiPath';

import type { RestRequest, ResponseComposition, DefaultBodyType, RestContext } from 'msw';

const getTodayChecklist = (
  req: RestRequest,
  res: ResponseComposition&amp;lt;DefaultBodyType&amp;gt;,
  ctx: RestContext
) =&amp;gt; {
  return res(ctx.status(200), ctx.json({ isTodayChecklistCreated: true }));
};

const checklistHandler = [rest.get(API_PATH.todayChecklist, getTodayChecklist)];

export default checklistHandler;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/api/checklist/today로 API를 요청하게 되면, { isTodayChecklistCreated: true } 라는 json을 반환하도록 getTodayChecklist 함수를 구현했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. worker를 설정해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1692594057474&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/mocks/browser.js
import { setupWorker } from 'msw'
import { handlers } from './handlers'

// This configures a Service Worker with the given request handlers.
export const worker = setupWorker(...handlers)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4.&amp;nbsp;worker를 시작한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692594101270&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/app/layout.tsx
if (process.env.NODE_ENV === 'development') {
  worker.start()
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식문서를 따라, 그리고 내가 이전 React 프로젝트에서 했던 것처럼 여기까지 하면 기본적인 세팅은 끝이고, 잘 될 줄 알았으나.. Next.js 13 환경에서는 그렇지 않았다. 에러의 시작이었다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 마주친 문제 1: 서버에서 worker를 시작할 수 없음&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;631&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cX785Z/btsrCyp3NZr/VsCCkVQkBZNJQvJwBNNuek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cX785Z/btsrCyp3NZr/VsCCkVQkBZNJQvJwBNNuek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cX785Z/btsrCyp3NZr/VsCCkVQkBZNJQvJwBNNuek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcX785Z%2FbtsrCyp3NZr%2FVsCCkVQkBZNJQvJwBNNuek%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;631&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RootLayout이 프로젝트의 진입점이기 때문에, 여기서 worker를 시작하면 될 거라고 생각했다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NODE_ENV를 활용해 개발 모드일 때에만 worker가 시작될 수 있도록 했다. 하지만 에러가 발생했다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;서버에서는 .start에 접근할 수 없다. 서버 컴포넌트에서는 클라이언트 모듈에 점(.)을 찍을 수 없다. import한 이름만 전달할 수 있다&amp;rdquo;&lt;/li&gt;
&lt;li&gt;즉 worker는 클라이언트 모듈이고 RootLayout은 서버 컴포넌트이기 때문에 위와 같은 에러가 발생하고 있는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. 원인: 서버 컴포넌트에서는 클라이언트 모듈을 사용할 수 없다&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Next.js는 CSR만 하는 게 아니라 SSR도 하기 때문에, 서버에서 실행되는 코드들이 있다.&lt;/li&gt;
&lt;li&gt;RootLayout은 서버 컴포넌트이기 때문에, 기본적으로 서버에서 렌더링된다.&lt;/li&gt;
&lt;li&gt;서버에는 worker가 존재하지 않기 때문에, worker라는 모듈을 찾을 수 없고, 당연히 worker를 시작할 수도 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. 해결 방법: 서버 환경과 브라우저 환경을 분기 처리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 환경인지, 브라우저 환경인지에 따라 분기처리를 해서 MSW를 실행해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// mocks/index.ts
export async function initBrowserMocks() {
  if (isBrowser) {
    const { worker } = await import('./browser');
    await worker.start();
  }
}

export async function initServerMocks() {
  if (!isBrowser) {
    const { server } = await import('./server');
    server.listen();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여기서 각 모듈을 import 할 때, 일반적으로 파일의 상단에 import를 하는 방식(static import)가 아닌, import() syntax를 활용하여 Dynamic import를 하고 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 문법을 통해 조건부로 모듈을 로드할 수 있게 된다.&lt;/li&gt;
&lt;li&gt;브라우저 환경에서는 브라우저와 관련된 모듈만, 서버 환경에서는 서버에 관련된 모듈만 로드한다.&lt;/li&gt;
&lt;li&gt;불필요한 리소스를 로드할 필요가 없게 되어, 초기 로딩 시간을 줄일 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 마주친 문제 2: 컴포넌트가 이미 렌더링 된 후 MSW 초기화&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이제 아까와 같은 Server Error가 뜨지 않았다! 모킹도 잘 되는 것 같았다.&lt;/li&gt;
&lt;li&gt;그런데 콘솔을 보니 빨갛게 에러가 뜨고 있었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kBxlz/btsrH8w70cZ/aFKlf1XBVeIi3davpZJaqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kBxlz/btsrH8w70cZ/aFKlf1XBVeIi3davpZJaqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kBxlz/btsrH8w70cZ/aFKlf1XBVeIi3davpZJaqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkBxlz%2FbtsrH8w70cZ%2FaFKlf1XBVeIi3davpZJaqk%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;176&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보니까 Mocking이 enabled가 되기도 전에 API 요청을 하고 있었다.&lt;/li&gt;
&lt;li&gt;Mocking enabled 이후에는 정상적으로 응답이 되고 있었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. 원인: 컴포넌트가 렌더링 된 후에 MSW가 초기화된다&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트가 이미 렌더링이 된 후에 MSW가 초기화되기 때문에 위와 같은 상황이 발생한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트가 렌더링이 되면서 API 요청이 발생하게 되고, 이때는 MSW가 초기화 되어있지 않기 때문에 API Request를 보낸다 하더라도 이것을 가로챌 수가 없다.&lt;/li&gt;
&lt;li&gt;따라서 404 에러가 발생한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. 해결 방법: 컴포넌트가 렌더링되기 전에 MSW를 초기화&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트가 렌더링되기 전에 MSW를 초기화시킬 수 있으려면, RootLayout에서 children 컴포넌트들이 렌더링 되기 전에 MSW를 실행할 수 있으면 된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그렇다면 MSW를 초기화하는 로직을 담은 컴포넌트를 만들고, 그 컴포넌트로 children을 감싸도록 하면 된다!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;// .env.local
NEXT_PUBLIC_API_MOCKING=enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;환경 변수에 다음과 같이 설정한다. 개발 모드일 때만 enabled로 설정하고, production 모드일 때는 설정해두지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/mocks/index.ts
export async function initMocks() {
  if (typeof window === 'undefined') {
    const { server } = await import('./server');
    server.listen();
  } else {
    const { worker } = await import('./browser');
    worker.start();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/mocks/MSWComponent.tsx
'use client';

import { useState, type PropsWithChildren, useEffect } from 'react';

const isMockingMode = process.env.NEXT_PUBLIC_API_MOCKING === 'enabled';

export const MSWComponent = ({ children }: PropsWithChildren) =&amp;gt; {
  const [mswReady, setMSWReady] = useState(() =&amp;gt; !isMockingMode);

  useEffect(() =&amp;gt; {
    const init = async () =&amp;gt; {
      if (isMockingMode) {
        const initMocks = await import('./index').then((res) =&amp;gt; res.initMocks);
        await initMocks();
        setMSWReady(true);
      }
    };

    if (!mswReady) {
      init();
    }
  }, [mswReady]);

  if (!mswReady) {
    return null;
  }

  return &amp;lt;&amp;gt;{children}&amp;lt;/&amp;gt;;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;initMocks 함수를 호출할 때는 await을 붙여서, 이 함수의 실행이 끝날 때까지 기다린 후 다음 코드 라인으로 넘어갈 수 있도록 해야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이렇게 해야 initMocks 함수 내부의 worker.start()가 호출되고 완료가 될 때까지 기다릴 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;개발 모드에서 MSWComponent를 실행하면
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;mswReady 상태 변수의 초기값은 !isMockingMode 값이므로 false가 된다.&lt;/li&gt;
&lt;li&gt;if (!mswReady)를 만족하므로, 컴포넌트는 null을 리턴한다.&lt;/li&gt;
&lt;li&gt;useEffect의 콜백 함수가 실행된다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;if (!mswReady)를 만족하므로 init 함수를 실행한다.&lt;/li&gt;
&lt;li&gt;init 함수가 실행되면 브라우저인지, 서버인지에 따라서 분기처리하여 MSW를 실행한다.&lt;/li&gt;
&lt;li&gt;mswReady 상태 변수를 true로 변경해준다.&lt;/li&gt;
&lt;li&gt;상태가 변경되었으니 MSWComponent를 리렌더링한다. children 컴포넌트가 렌더링된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Production 모드에서 MSWComponent를 실행하면
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;mswReady 상태 변수의 초기값은 true이다.&lt;/li&gt;
&lt;li&gt;&amp;lt;&amp;gt;{children}&amp;lt;/&amp;gt; 코드가 실행된다.&lt;/li&gt;
&lt;li&gt;useEffect의 콜백 함수가 실행된다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;if (!mswReady)를 만족하지 않으므로 init이 실행되지 않는다.&lt;/li&gt;
&lt;li&gt;결과적으로 아무것도 실행되지 않는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;이렇게 작성한 MSWComponent를 다음과 같이 RootLayout의 children을 감싸도록 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    &amp;lt;html lang=&quot;en&quot;&amp;gt;
      &amp;lt;body&amp;gt;
        &amp;lt;MSWComponent&amp;gt;
          {children}
        &amp;lt;/MSWComponent&amp;gt;
      &amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 정상적으로 children 컴포넌트들이 렌더링되기 전에 MSW를 초기화할 수 있게 되었다!&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAWAxF/btsrR5NiFzX/8ek8XYpyuCdLzgKFk0HYyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAWAxF/btsrR5NiFzX/8ek8XYpyuCdLzgKFk0HYyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAWAxF/btsrR5NiFzX/8ek8XYpyuCdLzgKFk0HYyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAWAxF%2FbtsrR5NiFzX%2F8ek8XYpyuCdLzgKFk0HYyK%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;140&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;140&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 부가적으로 알게 된 것&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. Dynamic import&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적으로 import를 한다는 것을 들어본 적은 있지만, 막상 활용을 해 본 적은 없는데 예시를 보니까 딱 감을 잡았다.&lt;/li&gt;
&lt;li&gt;서버인지, 클라이언트인지에 따라서 조건부로 로딩을 하고 싶을 때, 혹은 그런 경우가 아니더라도 모듈 크기가 크다면 우선 필요한 모듈만 로드하고 다른 작업을 수행하는 식으로도 활용할 수 있을 것이다.&lt;/li&gt;
&lt;li&gt;최적화를 할 때 고려해볼 수 있는 아주 좋은 방안이라는 생각이 들었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2. PropsWithChildren type&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;나는 보통 컴포넌트의 Props가 children을 가지고 있어야 할 때, children: ReactNode 이런 식으로 명시적으로 타입을 주곤 했다.&lt;/li&gt;
&lt;li&gt;그런데 콜라가 만든 MSWComponent를 참고하니, const MSWComponent = ({ children }: PropsWithChildren) 이런 식으로 활용할 수 있다는 것을 알게 되었다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름 자체는 굉장히 명확하다. children을 가지고 있는 props라는 뜻이니 말이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각 타입에 대해 궁금해져서 React 팀이 각 타입을 어떻게 정의해 놓았는지를 알아봤다. 실제로 타입들은 다음과 같이 구현되어 있었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type ReactNode =
        | ReactElement
        | string
        | number
        | Iterable&amp;lt;ReactNode&amp;gt;
        | ReactPortal
        | boolean
        | null
        | undefined
        | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES];

type PropsWithChildren&amp;lt;P = unknown&amp;gt; = P &amp;amp; { children?: ReactNode | undefined };&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PropsWithChildren 타입은 제네릭으로 인자를 받을 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;children 외에 추가적으로 다른 타입이 필요하다면 제네릭으로 전달하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다만 PropsWithChildren의 children 타입을 자세히 보면 optional이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉 이 말은, children이 없이 컴포넌트를 사용하더라도 에러가 나지 않는다는 것이다.&lt;/li&gt;
&lt;li&gt;만약 children이 반드시 있어야만 하는 컴포넌트라면, PropsWithChildren 타입을 사용하지 않는 편이 나을 수 있겠다.&lt;/li&gt;
&lt;li&gt;혹은 다음과 같은 type을 커스텀해서 만들어 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type PropsWithRequiredChildren&amp;lt;P = unknown&amp;gt; = P &amp;amp; { children: ReactNode | undefined }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. MSW를 더 알아보기 위해 참고하면 좋을 자료&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현업에서 MSW를 어떻게 사용하는지 알아볼 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://tech.kakao.com/2021/09/29/mocking-fe/&quot;&gt;https://tech.kakao.com/2021/09/29/mocking-fe/&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;카카오에서 MSW를 왜 도입했는지가 자세히 언급되고 있다. MSW를 사용하지 않고 Mocking을 했을 때 어떤 어려움을 겪었는지, MSW는 그 문제를 어떻게 해결해 주었는지가 나와 있다. 특히 MSW를 사용해서 현업에서 개발 과정이 어떻게 달라졌는지 상세히 풀어 쓰여져 있는 부분이 좋았다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tech.madup.com/mock-service-worker/&quot;&gt;https://tech.madup.com/mock-service-worker/&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API를 호출하는 로직이 포함된 코드를 테스트할 때, Mockup 처리를 하는 것이 매우 번거로워진다는 문제점이 있다. 이러한 문제점을 MSW를 사용하여 어떻게 해결했는지 과정이 담겨 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 해결하기 위해 &lt;a href=&quot;https://stackoverflow.com/questions/75614543/how-to-use-msw-with-nextjs-13-2-1-error-cannot-access-worker-start-on-the-serv&quot;&gt;StackOverFlow에 올라온 글&lt;/a&gt;이나 &lt;a href=&quot;https://github.com/mswjs/msw/issues/1644&quot;&gt;MSW GitHub Repository의 이슈&lt;/a&gt; 등도 찾아보면서, 나와 같은 개발 환경에서 MSW를 도입할 때 이러한 이슈를 겪게 된다는 것을 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜라 선생님의 도움과 함께 Next.js 13버전, 그리고 app 디렉토리를 사용하는 환경에서도 무사히 MSW를 적용하여 개발을 할 수 있게 되었다.  &amp;nbsp;앞으로 더 효율적으로 개발할 수 있게 되어 기대가 된다.&lt;/p&gt;</description>
      <category>Projects</category>
      <category>MSW</category>
      <category>next.js</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/382</guid>
      <comments>https://jaypedia.tistory.com/382#entry382comment</comments>
      <pubDate>Mon, 21 Aug 2023 14:08:23 +0900</pubDate>
    </item>
    <item>
      <title>알고리즘 스터디 42주차 - [프로그래머스] 크기가 작은 부분 문자열, [LeetCode] Assign Cookies</title>
      <link>https://jaypedia.tistory.com/381</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eyB9AG/btshAA5BpKy/imDYM63F672NFpcHkT5lMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eyB9AG/btshAA5BpKy/imDYM63F672NFpcHkT5lMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eyB9AG/btshAA5BpKy/imDYM63F672NFpcHkT5lMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeyB9AG%2FbtshAA5BpKy%2FimDYM63F672NFpcHkT5lMK%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;650&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/147355&quot;&gt;크기가 작은 부분 문자열&lt;/a&gt; (Level 1)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Problem Summary&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자로 이루어진 문자열인 t, p가 주어진다.&lt;/li&gt;
&lt;li&gt;t에서 p와 길이가 같은 부분 문자열 중, &lt;b&gt;부분 문자열이 나타내는 수&lt;/b&gt;가 p보다 작거나 같은 것이 몇 번 나오는지 횟수를 리턴한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Solution&lt;/h3&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;function solution(t, p) {
    let answer = 0;
    const length = p.length;
    const pNum = Number(p)

    for (let i = 0; i &amp;lt;= t.length - length; i++) {
        const curNum = Number(t.slice(i, i + length));
        if (curNum &amp;lt;= pNum) answer++;
    }

    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;p의 길이를 구해 놓고, p를 숫자로 변환시켜 놓는다.&lt;/li&gt;
&lt;li&gt;문자열 t를 순회한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이때 범위는 0부터 t.length - p.length이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;t가 &amp;ldquo;123456&amp;rdquo;이면 123, 234, 345, 456 이렇게 봐야 하기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;t를 순회하면서 slice 메서드를 사용하여 p의 길이만큼 curNum을 추출해낸다.&lt;/li&gt;
&lt;li&gt;curNum이 pNum보다 작거나 같으면 answer를 추가한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Result&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;3053&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGOKzj/btshA4eg5gz/JbYtFzIDmD1397YEMvbHV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGOKzj/btshA4eg5gz/JbYtFzIDmD1397YEMvbHV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGOKzj/btshA4eg5gz/JbYtFzIDmD1397YEMvbHV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGOKzj%2FbtshA4eg5gz%2FJbYtFzIDmD1397YEMvbHV0%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;340&quot; height=&quot;519&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;3053&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. &lt;a href=&quot;https://leetcode.com/problems/assign-cookies/&quot;&gt;Assign Cookies&lt;/a&gt; (LeetCode Easy)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Problem Summary&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Give each child at most one cookie - 각 어린이마다 &lt;b&gt;최대 하나&lt;/b&gt;의 쿠키를 줘야 함&lt;/li&gt;
&lt;li&gt;Each child i has a greed factor &lt;b&gt;g[i]&lt;/b&gt;, which is the &lt;b&gt;minimum size&lt;/b&gt; of a cookie that the child will be content with.&lt;/li&gt;
&lt;li&gt;Each cookie &lt;code&gt;j&lt;/code&gt; has a size &lt;code&gt;s[j]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If s[j] &amp;ge; g[i], we can assign the cookie j to the child i, and the child i will be content.&lt;/li&gt;
&lt;li&gt;Goal: &lt;b&gt;maximize&lt;/b&gt; the number of your &lt;b&gt;content children&lt;/b&gt; and output the maximum number&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Solution&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;var findContentChildren = function (g, s) {
  g.sort((a, b) =&amp;gt; a - b);
  s.sort((a, b) =&amp;gt; b - a);

  let answer = 0;

  for (let i = 0; i &amp;lt; g.length; i++) {
    if (!s.length) return answer;
    const child = g[i];

    while (s.length) {
      const cookie = s.pop();
      if (child &amp;lt;= cookie) {
        answer++;
        break;
      } else {
        continue;
      }
    }
  }

  return answer;
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Idea: 최대한 많은 아이를 만족 &amp;rarr; 정렬해서 적은 쿠키를 원하는 아이부터 만족시키기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아이는 오름차순, 쿠키는 내림차순(shift 대신 pop 하면서 하나씩 없앨 거라서)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;현재 쿠키를 pop으로 뽑아 주고, child가 원하는 값과 같거나 큰지 비교한 후
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;충족되면 answer를 증가시켜주고 break&lt;/li&gt;
&lt;li&gt;미충족되면 다시 pop으로 넘어가기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Another solution&lt;/h3&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://leetcode.com/problems/assign-cookies/solutions/432753/javascript-greedy-faster-99-3-space-100/&quot;&gt;https://leetcode.com/problems/assign-cookies/solutions/432753/javascript-greedy-faster-99-3-space-100/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;var findContentChildren = function(g, s) {
    g = g.sort((a,b) =&amp;gt; a-b)
    s = s.sort((a,b) =&amp;gt; a-b)

    let i=0 // cookie index
    let count = 0;
    let j=0 // child index
    while(i&amp;lt;s.length){
        if(s[i] &amp;gt;= g[j]){
            count++
            j++
        }
        i++
    }

    return count
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pop 연산, 중첩된 while 문 등이 없기 때문에 좀 더 효율적인 풀이.&lt;/li&gt;
&lt;li&gt;i, j 인덱스를 0부터 따로 두고
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조건이 충족된다면 child의 인덱스를 올리고, 충족되지 않으면 cookie의 인덱스를 올리는 식으로 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Result&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;959&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF9ryv/btshzCQfZ6l/YfOo4ObeF3ftmQ15zA1bp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF9ryv/btshzCQfZ6l/YfOo4ObeF3ftmQ15zA1bp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF9ryv/btshzCQfZ6l/YfOo4ObeF3ftmQ15zA1bp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF9ryv%2FbtshzCQfZ6l%2FYfOo4ObeF3ftmQ15zA1bp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;959&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;959&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Algorithms</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/381</guid>
      <comments>https://jaypedia.tistory.com/381#entry381comment</comments>
      <pubDate>Sun, 28 May 2023 18:16:41 +0900</pubDate>
    </item>
    <item>
      <title>[Pullanner] 프론트엔드 개발 환경 세팅 과정 Part 1. Formatting &amp;amp; Code Quality</title>
      <link>https://jaypedia.tistory.com/380</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-04-30 at 12.05.06 AM.png&quot; data-origin-width=&quot;1815&quot; data-origin-height=&quot;1016&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pzBlj/btsdi3pk3iZ/BeItpyvq3KalxiBweQcUkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pzBlj/btsdi3pk3iZ/BeItpyvq3KalxiBweQcUkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pzBlj/btsdi3pk3iZ/BeItpyvq3KalxiBweQcUkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpzBlj%2Fbtsdi3pk3iZ%2FBeItpyvq3KalxiBweQcUkk%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;1815&quot; height=&quot;1016&quot; data-filename=&quot;Screenshot 2023-04-30 at 12.05.06 AM.png&quot; data-origin-width=&quot;1815&quot; data-origin-height=&quot;1016&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Introduction&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀래너의 프론트엔드 팀은 개발 환경을 세팅할 때 많은 공을 들였습니다.  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;89일 간 13번의 심도 있는 회의를 통해서, 현재는 개발 환경 세팅이 완료된 상태입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;1238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p62UL/btsdds4YWvp/uxf5Bt0ZSABvlTYm2UsclK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p62UL/btsdds4YWvp/uxf5Bt0ZSABvlTYm2UsclK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p62UL/btsdds4YWvp/uxf5Bt0ZSABvlTYm2UsclK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp62UL%2Fbtsdds4YWvp%2Fuxf5Bt0ZSABvlTYm2UsclK%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;547&quot; height=&quot;494&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;1238&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 Formatting과 Code Quality와 관련된 세팅을 어떻게 했는지에 대해서 자세히 파헤쳐 보려고 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Code Formatter와 Linter를 도입한 이유&lt;/h2&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;그래서 ESLint, Prettier는 필수라고 생각을 했고, 이제 이것들을 어떻게 우리 팀에 맞게 커스터마이징하여 사용할 것인가를 고민했어요.&lt;/li&gt;
&lt;li&gt;코드를 본격적으로 작성하기 전에 충분히 고민을 한다면, 앞으로 코드를 작성할 때 확실히 스타일에 대한 고민을 줄일 수 있고 로직 작성에 더 집중해서 속도를 높일 수 있을 거라 생각했어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Linting은 ESLint에게, Code Formatting은 Prettier에게 맡기자!&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ESLint에도 코드 포맷팅 기능이 있지만, Prettier의 자동 코드 포맷팅 기능이 더 강력해요.&lt;/li&gt;
&lt;li&gt;저희 팀은 &lt;code&gt;eslint-config-prettier&lt;/code&gt; 플러그인을 설치해서, eslint에서 formatting 관련한 rule들을 모두 해제했어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ESLint와 Prettier가 자동으로 적용될 수 있게 하자!&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Git Hook을 좀 더 편리하게 사용할 수 있는 도구인 Husky와 Lint-staged를 활용해서, 커밋을 할 때 ESLint와 Prettier가 적용된 후에 커밋이 수행될 수 있도록 설정했어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ESLint 설정&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ESLint에 사용한 extends와 rules를 정리해 보았어요.&lt;/li&gt;
&lt;li&gt;extends는 무슨 역할을 하는지, rules는 왜 적용했는지 하나하나 알아보고 정리했답니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용한 extends 목록&lt;/h3&gt;
&lt;table id=&quot;f75f33cd-d8c4-40a2-b97f-3717e275a3a4&quot; style=&quot;border-collapse: collapse; width: 100%; height: 982px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.3024%;&quot;&gt;&lt;b&gt;Module Name&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.2558%;&quot;&gt;&lt;b&gt;eslintrc.cjs&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;&lt;b&gt;Description&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.3489%;&quot;&gt;&lt;b&gt;Examples&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;7f39b9ca-c71c-4081-972b-b08952ede8e9&quot; style=&quot;height: 115px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 115px;&quot;&gt;eslint-plugin-jsx-a11y&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 115px;&quot;&gt;plugin:jsx-a11y/recommended&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 115px;&quot;&gt;JSX를 정적으로 평가(static evaluation)하여 애플리케이션의 접근성 문제를 찾아주는 플러그인&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 115px;&quot;&gt;&lt;b&gt;&amp;bull;&lt;/b&gt; alt-text 룰을 통해 img 태그 등에 alternative text를 명시하지 않을 시 에러를 발생시켜, 사용자가 요소를 볼 수 없는 상황일 경우 대체할 정보를 표시할 수 있도록 한다. &lt;br /&gt;&lt;b&gt;&amp;bull;&lt;/b&gt; no-noninteractive-element-interactions룰을 통해 interactive element가 아닌 div 태그 등에 mouse나 keyboard event handler를 할당하지 못하도록 에러를 발생시킨다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;a7a527fe-fa73-4d7f-aefd-fa949cbc814a&quot; style=&quot;height: 75px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 75px;&quot;&gt;&lt;a href=&quot;https://github.com/import-js/eslint-plugin-import&quot;&gt;eslint-plugin-import&lt;/a&gt; &lt;a href=&quot;https://github.com/import-js/eslint-import-resolver-typescript&quot;&gt;eslint-import-resolver-typescript&lt;/a&gt;&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 75px;&quot;&gt;plugin:import/typescript&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 75px;&quot;&gt;eslint-import-resolver-plugin은 eslint-plugin-import에 TypeScript 지원을 추가한다.&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 75px;&quot;&gt;&amp;bull; &amp;nbsp;.cts/.mts/.ts/.tsx/.d.cts/.d.mts/.d.ts 확장자를 가진 파일을 import/require 할 수 있다. &lt;br /&gt;&amp;bull; &amp;nbsp;tsconfig.json에 정의된 paths를 사용할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;08d8b352-92f2-4f5b-9fff-5979b6479a76&quot; style=&quot;height: 134px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 134px;&quot;&gt;&lt;a href=&quot;https://github.com/typescript-eslint/typescript-eslint&quot;&gt;&lt;b&gt;typescript-eslint&lt;/b&gt;&lt;/a&gt;&lt;b&gt; &lt;/b&gt;@typescript-eslint/parser&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 134px;&quot;&gt;plugin:@typescript-eslint/recommended&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 134px;&quot;&gt;ESLint, Pretter가 TypeScript를 지원할 수 있도록 하는 도구&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 134px;&quot;&gt;&amp;bull; &lt;a href=&quot;https://typescript-eslint.io/rules/no-inferrable-types/&quot;&gt;no-inferrable-types&lt;/a&gt;: number, string, boolean 등으로 초기화 된 변수나 매개 변수에 명시적으로 유형을 선언하지 않도록 강제하는 규칙. TypeScript는 이러한 경우 타입을 유추할 수 있다. 명시적으로 type annotation을 사용하면 코드가 불필요하게 장황하게 되어 가독성이 떨어진다. 또한 일반적인 기본 유형(e.g. number)보다 구체적인 literal type(e.g. number)을 추론하지 못하게 될 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;59f9c705-1aa8-4438-9f22-926db31616aa&quot; style=&quot;height: 96px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 96px;&quot;&gt;&lt;a href=&quot;https://github.com/import-js/eslint-plugin-import&quot;&gt;eslint-plugin-import&lt;/a&gt;&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 96px;&quot;&gt;plugin:import/recommended&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 96px;&quot;&gt;적절하게 import를 할 수 있도록 유효성을 검사하는 규칙을 가지고 있는 ESLint 플러그인. file path나 스펠링이 틀린 것도 잡아낼 수 있음&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 96px;&quot;&gt;&lt;b&gt;&amp;bull; &lt;/b&gt;&lt;a href=&quot;https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md&quot;&gt;no-extraneous-dependencies&lt;/a&gt; : 외부 패키지 사용을 금지한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;80578f0c-514c-466d-9617-3dce3f49f3ab&quot; style=&quot;height: 56px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 56px;&quot;&gt;&lt;a href=&quot;https://github.com/eslint/eslint&quot;&gt;&lt;b&gt;eslint&lt;/b&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 56px;&quot;&gt;eslint:recommended&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 56px;&quot;&gt;ESLint 팀에서 best practice로 간주하는 규칙이 포함된 built-in configuration&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 56px;&quot;&gt;&amp;bull; no-const-assign: const variable에 재할당을 금지한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;f0862a43-b960-40ac-b8e9-80ea090d2a4a&quot; style=&quot;height: 38px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 38px;&quot;&gt;&lt;a href=&quot;https://github.com/jsx-eslint/eslint-plugin-react&quot;&gt;&lt;b&gt;eslint-plugin-react&lt;/b&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 38px;&quot;&gt;plugin:react/recommended&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 38px;&quot;&gt;React에 특화된 ESLint 규칙&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 38px;&quot;&gt;&amp;bull; &lt;a href=&quot;https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/button-has-type.md&quot;&gt;button-has-type&lt;/a&gt;: 명시적으로 type attribute를 쓰지 않고 button element를 사용하는 것을 금지한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;6c16a85e-19f8-4358-b6c4-49bf901f79bf&quot; style=&quot;height: 96px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 96px;&quot;&gt;&lt;a href=&quot;https://github.com/jsx-eslint/eslint-plugin-react&quot;&gt;&lt;b&gt;eslint-plugin-react&lt;/b&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 96px;&quot;&gt;plugin:react/jsx-runtime&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 96px;&quot;&gt;&lt;a href=&quot;https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html&quot;&gt;React 17의 새로운 JSX transform&lt;/a&gt;을 사용하는 경우, 이 플러그인을 extends에 명시하여 관련 규칙을 비활성화해야 함&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 96px;&quot;&gt;&amp;bull; &lt;a href=&quot;https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md&quot;&gt;react-in-jsx-scope&lt;/a&gt;: JSX를 사용할 때 React를 꼭 import 해와야 하는 규칙. React 17 버전 이상을 사용하는 경우 이 규칙을 off하여 해제한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;5223f20d-b6e9-4a15-878d-37f99621dbe4&quot; style=&quot;height: 134px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 134px;&quot;&gt;&lt;a href=&quot;https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks&quot;&gt;eslint-plugin-react-hooks&lt;/a&gt;&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 134px;&quot;&gt;plugin:react-hooks/recommended&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 134px;&quot;&gt;React Hook의 2가지 규칙을 적용하는 ESLint plugin (&lt;a href=&quot;https://legacy.reactjs.org/docs/hooks-rules.html&quot;&gt;Reference: Rules of Hooks&lt;/a&gt;)&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 134px;&quot;&gt;&amp;bull; Hook은 Top Level에서만 호출 가능: loops, conditions, nested functions 내부에서 Hook을 호출하면 안 된다는 규칙. 이 규칙을 통해 컴포넌트가 렌더링 될 때마다 Hook이 동일한 순서로 호출되도록 할 수 있다. 또한 React는 여러 번의 useState와 useEffect 호출 사이에 Hook의 상태를 올바르게 보존할 수 있다. &amp;bull; React function component 및 custom Hook에서만 Hook 호출이 가능하다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;ab0be602-72c8-41e1-ad3e-6a1b0383f40f&quot; style=&quot;height: 76px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 76px;&quot;&gt;&lt;a href=&quot;https://github.com/prettier/eslint-config-prettier&quot;&gt;&lt;b&gt;eslint-config-prettier&lt;/b&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 76px;&quot;&gt;plugin:prettier/recommended&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 76px;&quot;&gt;Prettier와의 충돌을 방지하기 위해 code formatting과 관련된 ESLint rule을 비활성화한다.&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 76px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;faf5fb1d-8ef1-462a-aa93-c9bfdc4251a4&quot; style=&quot;height: 96px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 96px;&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/eslint-config-airbnb&quot;&gt;eslint-config-airbnb&lt;/a&gt;&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 96px;&quot;&gt;airbnb&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 96px;&quot;&gt;eslint-config-airbnb는 Airbnb의 .eslintrc를 확장이 가능한 공유된 config로서 제공하는 패키지&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 96px;&quot;&gt;&amp;bull; 익명 함수를 사용해야 하는 경우(inline callback 등) 함수 선언문이 아닌 화살표 함수 표현식을 사용하도록 강제한다. (eslint: prefer-arrow-callback, arrow-spacing) 화살표 함수는 해당 컨텍스트의 this에서 실행하는 버전의 함수를 만들기 때문에 보통 원하는 대로 작동한다. 또한 문법이 간결해진다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;e9b7981b-0018-4db3-8607-8c306661beb9&quot; style=&quot;height: 56px;&quot;&gt;
&lt;td id=&quot;ur@S&quot; style=&quot;width: 19.3024%; height: 56px;&quot;&gt;&lt;a href=&quot;https://github.com/storybookjs/eslint-plugin-storybook&quot;&gt;&lt;b&gt;eslint-plugin-storybook&lt;/b&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td id=&quot;EsI?&quot; style=&quot;width: 13.2558%; height: 56px;&quot;&gt;plugin:storybook/recommended&lt;/td&gt;
&lt;td id=&quot;Ij?C&quot; style=&quot;width: 22.093%; height: 56px;&quot;&gt;Storybook을 Best practice로 사용하기 위한 공식적인 ESLint plugin&lt;/td&gt;
&lt;td id=&quot;mLVH&quot; style=&quot;width: 45.3489%; height: 56px;&quot;&gt;&amp;bull; &lt;a href=&quot;https://github.com/storybookjs/eslint-plugin-storybook/blob/main/docs/rules/default-exports.md&quot;&gt;storybook/default-exports&lt;/a&gt;: Story file에는 default export가 있어야 한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용한 rules 목록&lt;/h3&gt;
&lt;table id=&quot;56bd3038-29d7-477f-aeb9-3421fc1604b2&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.3721%;&quot;&gt;Rules&lt;/td&gt;
&lt;td style=&quot;width: 33.3722%;&quot;&gt;Description&lt;/td&gt;
&lt;td style=&quot;width: 48.2558%;&quot;&gt;Reason&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;e0b99922-8ea7-481a-b6ce-323c57d5ff8f&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;no-warning-comments&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;설정에 명시된 특정한 단어를 포함하고 있는 주석에 대해 보고하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;커밋하기 전에 &amp;lsquo;TODO&amp;rsquo;, &amp;lsquo;FIXME&amp;rsquo;, &amp;lsquo;XXX&amp;rsquo;, &amp;lsquo;BUG&amp;rsquo; 주석에 있을 경우 보고 받아서 주석을 제거할 수 있게 이 규칙을 적용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;3ebefb1d-9dec-49a3-a086-ea58c7cee3a1&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;import/order&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;require나 import 문의 순서 컨벤션을 정하고 그것을 강제하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;import 문의 순서 컨벤션을 사용하면 코드의 가독성이 좋아지므로 이 규칙을 적용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;a8375cac-500a-4ef2-857f-e195a927157e&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;react/function-component-definition&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;함수 컴포넌트를 사용할 때 특정한 함수 타입을 적용하도록 도와주는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;컨벤션에서 함수를 arrow function을 사용해서 정의하기로 결정했기 때문에, 함수 컴포넌트 정의시 arrow function을 사용하도록 이 규칙을 적용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;d23a8d64-ab66-41db-ba68-2caf7fbb9e4b&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;no-console&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;console의 사용을 금지하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;console.log를 사용하여 에러를 확인하는 것은 git commit 전 확인하는데 유용하므로, console을 사용하기로 결정해서 이 규칙을 비활성화 했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;e636526d-8f0e-49fa-999e-3aa70f5df77f&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;react/jsx-filename-extension&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;JSX 문법 포함하는 파일이 .jsx 확장자를 사용하도록 권장하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;jsx 확장자를 통해 파일에서 JSX 문법을 사용하는지 한번에 알아볼 수 있으므로 이 규칙을 적용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;8807f51e-8e08-4632-a0d4-35cd81aa2127&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;import/prefer-default-export&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;export하는 파일 내에서 default export를 사용하도록 권장하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;default export를 사용하면 intellisense가 잘 작동하지 않아서 불편하기 때문에, default export를 사용하지 않기로 결정하여 이 규칙을 비활성화 했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;0ae31fa5-361c-4e42-9d14-7b8839b0cf78&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;no-plusplus&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;단항 연산자 ++, &amp;mdash;를 허용하지 않는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;단항 연산자는 자동 semi-colon(;) 삽입 대상이어서 공백의 차이로 인해 소스 코드의 의미 체계가 달라질 수 있으므로, 단항 연산자를 사용하지 않도록 이 규칙을 적용했습니다. 그러나 for 문에서의 단항 연산자는 semi-colon 없이 사용하므로, allowForLoopAfterthoughts 옵션을 통해 단항 연산자를 허용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;3f24fc0d-6fd6-460b-b2d5-c9673947c098&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;react/require-default-props&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;컴포넌트의 props가 required 타입이 아닐 때 대응되는 defaultProps값을 설정하도록 강제하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;프로젝트에서 TypeScript를 사용하기 때문에, defaultProps 값이 필요 없으므로 이 규칙을 비활성화 했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;0ff94190-35ec-4e34-ae07-85394ef612eb&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;react/prop-types&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;컴포넌트의 props에 대한 타입인 propTypes을 설정하도록 강제하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;프로젝트에서 TypeScript를 사용하기 때문에, propTypes 값이 필요 없으므로 이 규칙을 비활성화 했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;8e9ee27a-583d-40c8-b428-3ad5840a73c5&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;consistent-return&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;return 문을 사용하도록 강제하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;return 문이 필요 없는 경우도 존재하므로 이 규칙을 비활성화 했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;1c6962e7-136c-4e3c-b8d3-83742498e4f0&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;curly&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;모든 block 문에 대해 일관적인 괄호({}) 스타일을 강제하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;모든 block 문을 괄호로 감싸는 일관적인 스타일을 적용하여 코드의 가독성을 높이기 위해 이 규칙을 적용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;3ae210db-0cf6-4ebb-8a28-eab628f44445&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;eqeqeq&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;strick equality operator(===, &amp;ne;=)를 사용하도록 강제하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;타입 변환을 일으키는 eqaulity operator(==, &amp;ne;) 대신에 stict equality operator(===, &amp;ne;=)를 사용하는 것이 안전하기 때문에 이 규칙을 적용했습니다. smart 옵션을 사용하여 literal 값을 비교할 때, typeof 연산자의 반환값을 평가할 때, null과 비교할 때의 3가지 경우에 이 규칙이 적용되지 않도록 했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;cd6b1f17-06cc-4c2d-900f-923380e15283&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;@typescript-eslint/naming-convention&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;코드 전반에 네이밍 컨벤션을 강제하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;기존에 논의한 네이밍 컨벤션을 강제함으로써 코드의 가독성이 좋아지므로 이 규칙을 적용했습니다. 사용하지 않는 변수나 매개변수를 정의할 때 underscore(_)로 시작하는 이름을 붙이기 때문에, 변수와 매개변수에 leadingUnderscore 옵션을 사용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;95cbeee1-c4c6-4a46-b0c7-1cec0423d962&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;@typescript-eslint/array-type&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;배열 타입을 일관적으로 정의하도록 강제하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;모든 배열 타입을 T[]의 형태로 정의함으로써 코드의 가독성이 좋아지므로 이 규칙을 적용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;89b416c6-30f9-4abf-8792-484167a81705&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;no-unused-vars&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;변수가 사용되지 않는 것을 허용하지 않는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;사용되지 않는 변수는 코드에서 자리를 차지하고 가독성을 헤치므로, 이러한 경우를 방지하기 위해 이 규칙을 적용했습니다. 사용하지 않는 인수나 구조 분해 할당 시 사용하지 않는 변수를 underscore(_)로 정의하기 때문에, argsIgnorePattern: &amp;lsquo;^_&amp;rsquo; 과 destructredArrayIgnoerPattern : &amp;lsquo;^_' 옵션을 사용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;a2462411-8f94-42d4-9365-85460566cd3d&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;react/react-in-jsx-scope&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;JSX를 사용할 때 scope 내에 React가 있는지 확인하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;React 17 버전 이후부터 새로운 JSX transfom에서 자동적으로 react/jsx-runtime 함수를 불러오기 때문에, 이 규칙을 비활성화 했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;4a7d39f6-836e-453d-a272-1100be5216df&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;arrow-body-style&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;arrow function의 내부를 괄호로 감싸도록 강제하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;arrow function의 내부를 항상 괄호로 감싸는 일관적인 스타일을 적용하여 코드의 가독성을 높이기 위해 이 규칙을 적용했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;abe1f47e-aaea-48d5-886e-b42c77cdbdb3&quot;&gt;
&lt;td id=&quot;OOPY&quot; style=&quot;width: 18.3721%;&quot;&gt;import/extensions&lt;/td&gt;
&lt;td id=&quot;vyow&quot; style=&quot;width: 33.3722%;&quot;&gt;source path를 import할 때 파일 확장자의 사용 여부를 결정하는 규칙&lt;/td&gt;
&lt;td id=&quot;?Z&amp;gt;l&quot; style=&quot;width: 48.2558%;&quot;&gt;typescript resolver가 import 경로에서 파일 확장자의 생략을 허용하므로, import 경로에 파일 확장자를 사용하지 않도록 이 규칙을 적용했습니다. 추후에 이미지 파일 import 시 이미지 파일임을 구분하기 위해 특정 파일 확장자를 사용할 예정입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>Projects/Pullanner</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/380</guid>
      <comments>https://jaypedia.tistory.com/380#entry380comment</comments>
      <pubDate>Sun, 30 Apr 2023 00:28:45 +0900</pubDate>
    </item>
    <item>
      <title>알고리즘 스터디 40주차 - [프로그래머스] 방문 길이, 점프와 순간 이동</title>
      <link>https://jaypedia.tistory.com/378</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5m467/btsdhyXpvhL/aXmPzV3rmROJK3oKWIhO11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5m467/btsdhyXpvhL/aXmPzV3rmROJK3oKWIhO11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5m467/btsdhyXpvhL/aXmPzV3rmROJK3oKWIhO11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5m467%2FbtsdhyXpvhL%2FaXmPzV3rmROJK3oKWIhO11%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;650&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/49994&quot;&gt;방문 길이&lt;/a&gt; (Level 2)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Problem Summary&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명령어가 주어진다. 이 명령어대로 캐릭터는 움직이고, &amp;ldquo;처음 걸어본 길의 길이&amp;rdquo;를 구해야 한다.&lt;/li&gt;
&lt;li&gt;좌표평면의 경계를 넘어가는 명령어는 무시한다.&lt;/li&gt;
&lt;li&gt;캐릭터는 0,0에서 시작하고, 경계는 5, -5이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Solution&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function solution(dirs) {
  let answer = 0;
  const loc = { x: 0, y: 0 };
  const set = new Set();

  for (const dir of dirs) {
    const curLoc = `${loc.x}${loc.y}`;
    switch (dir) {
      case 'U':
        loc.y &amp;lt; 5 &amp;amp;&amp;amp; loc.y++;
        break;
      case 'D':
        loc.y &amp;gt; -5 &amp;amp;&amp;amp; loc.y--;
        break;
      case 'R':
        loc.x &amp;lt; 5 &amp;amp;&amp;amp; loc.x++;
        break;
      case 'L':
        loc.x &amp;gt; -5 &amp;amp;&amp;amp; loc.x--;
        break;
    }
    const movedLoc = `${loc.x}${loc.y}`;
    const path = curLoc + movedLoc;
    const anotherPath = movedLoc + curLoc;

    if (!set.has(path) &amp;amp;&amp;amp; !set.has(anotherPath) &amp;amp;&amp;amp; curLoc !== movedLoc) {
      answer++;
      set.add(path);
      set.add(anotherPath);
    }
  }

  return answer;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Time Complexity&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;O(N)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;N: dirs의 길이&lt;/li&gt;
&lt;li&gt;주어진 dirs 문자열을 한 번 반복하면서 연산함&lt;/li&gt;
&lt;li&gt;입력 크기에 비례하여 선형적으로 실행 시간 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Another solution&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function solution(dirs) {
  let loc = { x: 0, y: 0 };
  const dirMap = {
    U: { direction: 'y', value: 1 },
    D: { direction: 'y', value: -1 },
    R: { direction: 'x', value: 1 },
    L: { direction: 'x', value: -1 },
  };

  const pathSet = new Set();

  for (const dir of dirs) {
    const { direction, value } = dirMap[dir];
    const moved = loc[direction] + value;
    if (moved &amp;gt; 5 || moved &amp;lt; -5) continue;
    const movedLoc = { ...loc };
    movedLoc[direction] = moved;
    pathSet.add(`${loc.x}${loc.y}${movedLoc.x}${movedLoc.y}`);
    pathSet.add(`${movedLoc.x}${movedLoc.y}${loc.x}${loc.y}`);
    loc = movedLoc;
  }
  return pathSet.size / 2;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pathSet에 방문한 길을 저장하는 방식&lt;/li&gt;
&lt;li&gt;answer 변수를 따로 쓸 필요가 없어짐&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Result&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;2719&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/el8GN8/btsdd0UD8CP/GxKsw34iP1VHymj42ZSl9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/el8GN8/btsdd0UD8CP/GxKsw34iP1VHymj42ZSl9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/el8GN8/btsdd0UD8CP/GxKsw34iP1VHymj42ZSl9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fel8GN8%2Fbtsdd0UD8CP%2FGxKsw34iP1VHymj42ZSl9K%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;359&quot; height=&quot;488&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;2719&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12980&quot;&gt;점프와 순간 이동&lt;/a&gt; (Level 2)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Problem Summary&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 번에 K칸 앞으로 점프 or (현재까지 온 거리) x 2에 해당하는 위치로 순간이동&lt;/li&gt;
&lt;li&gt;순간이동은 건전지 사용 안줄음 (더 효율적)&lt;/li&gt;
&lt;li&gt;K칸 점프는 K만큼 건전지 사용량 필요&lt;/li&gt;
&lt;li&gt;거리가 N만큼 떨어져 있는 거리 가려고 함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;점프는 최소화 &amp;rarr; 건전지 사용량의 최솟값&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Solution&lt;/h3&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;function solution(n) {
  let ans = 0;

  while (n) {
    if (n % 2) {
      ans++;
      n--;
      continue;
    }
    n = n / 2;
  }

  return ans;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주어진 값을 계속 2로 나눠 주는 접근 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2로 나눴을 때 나머지가 있으면, -1을 한 후, 건전지 사용량을 1 증가시킨다.&lt;/li&gt;
&lt;li&gt;2로 나눴을 때 나머지가 없으면(즉 나누어 떨어지면) 순간이동한다.(2로 나눠준 값을 할당한다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Time Complexity&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;O(log n)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;루프를 매번 돌 때마다 n은 2로 나눠지거나 1이 감소하게 된다. 2로 나눠지면서 n의 값이 반으로 줄어들기 때문에 시간 복잡도가 O(log n)이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Another solution&lt;/h3&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;function solution(n) {
  return n.toString(2).replace(/0/g, '').length;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 수를 2로 나누고, 그 몫을 또다시 2로 나누며 나오는 나머지들의 합은, 그 수를 이진수로 변환한 후의 1의 개수와 같음을 이용한 풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Result&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;3787&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8O4Q9/btsdhAATzIF/sCwa1Mdnk8QgLkYtVDR7i0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8O4Q9/btsdhAATzIF/sCwa1Mdnk8QgLkYtVDR7i0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8O4Q9/btsdhAATzIF/sCwa1Mdnk8QgLkYtVDR7i0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8O4Q9%2FbtsdhAATzIF%2FsCwa1Mdnk8QgLkYtVDR7i0%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;328&quot; height=&quot;621&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;3787&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Algorithms</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/378</guid>
      <comments>https://jaypedia.tistory.com/378#entry378comment</comments>
      <pubDate>Sun, 30 Apr 2023 00:02:52 +0900</pubDate>
    </item>
    <item>
      <title>Pullanner: Pull-up Planner, 풀업 운동 메이트 '풀래너'를 소개합니다 </title>
      <link>https://jaypedia.tistory.com/377</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1821&quot; data-origin-height=&quot;1020&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pr66w/btsdeZ8N4Co/BqDWIScXAOuEoCdOU0X01K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pr66w/btsdeZ8N4Co/BqDWIScXAOuEoCdOU0X01K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pr66w/btsdeZ8N4Co/BqDWIScXAOuEoCdOU0X01K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpr66w%2FbtsdeZ8N4Co%2FBqDWIScXAOuEoCdOU0X01K%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;1821&quot; height=&quot;1020&quot; data-origin-width=&quot;1821&quot; data-origin-height=&quot;1020&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Introduction&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pull-up Planner, 줄여서 Pullanner(풀래너)는 풀업 운동을 차근차근 해나갈 수 있도록 도와주는 서비스입니다.&lt;br /&gt;풀업 운동은 상체 근력을 키우는 데 아주 좋은 운동이지만, 꽤나 쉽지만은 않은 운동이기 때문에 초보자가 하려면 꾸준함과 노력이 필요해요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;1032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIhA1L/btsddZuFPG7/nf7SKFAZMZGKyeLQSo6MFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIhA1L/btsddZuFPG7/nf7SKFAZMZGKyeLQSo6MFk/img.png&quot; data-alt=&quot;풀래너 와이어프레이밍의 일부 - 계속 발전 중!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIhA1L/btsddZuFPG7/nf7SKFAZMZGKyeLQSo6MFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIhA1L%2FbtsddZuFPG7%2Fnf7SKFAZMZGKyeLQSo6MFk%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;1754&quot; height=&quot;1032&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;1032&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;작년 10월부터 프론트엔드 개발자, 백엔드 개발자, 그리고 디자이너가 모여 서비스 기획을 시작했고, 지금도 프로젝트가 진행되고 있습니다.&lt;br /&gt;저는 프론트엔드 개발자로서 기획, 디자인에도 참여하고 있는데요! 개발이 아닌 다른 분야도 팀원들과 함께하니 즐거웠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Future&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 프론트엔드 개발 과정을 블로그에 담아 볼 예정입니다.&lt;br /&gt;개발환경 세팅 과정, 개발 과정, 트러블 슈팅 과정 등, 기술과 관련된 이야기들을 꼼꼼하게 적어 볼 거에요.&lt;br /&gt;풀래너 서비스가 어떻게 발전해 나갈지, 기대가 됩니다  &lt;/p&gt;</description>
      <category>Projects/Pullanner</category>
      <category>풀래너</category>
      <category>프로젝트</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/377</guid>
      <comments>https://jaypedia.tistory.com/377#entry377comment</comments>
      <pubDate>Sat, 29 Apr 2023 23:16:49 +0900</pubDate>
    </item>
    <item>
      <title>알고리즘 스터디 39주차 - [프로그래머스] 광물 캐기, 할인 행사, 대충 만든 자판</title>
      <link>https://jaypedia.tistory.com/376</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;알고리즘-2022-002.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TR96w/btsb6Z2vRdi/ANvwkN9pKp4zfQe1q7mbwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TR96w/btsb6Z2vRdi/ANvwkN9pKp4zfQe1q7mbwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TR96w/btsb6Z2vRdi/ANvwkN9pKp4zfQe1q7mbwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTR96w%2Fbtsb6Z2vRdi%2FANvwkN9pKp4zfQe1q7mbwK%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;650&quot; data-filename=&quot;알고리즘-2022-002.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131127&quot;&gt;할인 행사&lt;/a&gt; (Level 2)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Problem Summary&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;want 배열에 있는 제품과 수량이 &lt;b&gt;할인하는 날짜와 10일 연속으로 일치&lt;/b&gt;할 경우의 수 구하기&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Solution&lt;/h3&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;function solution(want, number, discount) {
// 1. 물건과 물건의 개수를 매핑하기 
  const wantMap = want.reduce((map, el, idx) =&amp;gt; {
    map.set(el, number[idx]);
    return map;
  }, new Map());

  let count = 10; // 물건 10개가 모두 할인되는지 체크해 줄 변수 
  let answer = 0;

  discount.forEach((_, i) =&amp;gt; {
// 10개를 체크해줘야 하므로 이런 식으로 범위 정함 
// 지금 시작하는 값으로부터 10개 이상일 때에만 체크함 
    if (discount.length - i &amp;gt;= 10) {
      for (let j = i; j &amp;lt;= i + 10; j++) {
        const cur = discount[j];
        if (!wantMap.has(cur)) break; // 없는 품목이 있으면 바로 break
        if (wantMap.get(cur) &amp;lt;= 0) break; // 개수가 0이면 수량 안맞으니 break
        wantMap.set(cur, wantMap.get(cur) - 1); // wantMap의 해당 개수 감소 
        count -= 1;
      }

// 10개를 다 체크한 후 count가 10인지 확인 및 다시 채워주는 작업 
      if (count === 0) answer++;
      count = 10;
      want.forEach((v, i) =&amp;gt; {
        wantMap.set(v, number[i]);
      });
    }
  });

  return answer;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Time Complexity&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;O(N^2)&lt;/li&gt;
&lt;li&gt;discount 최대 길이가 10만이므로 10만의 제곱은 100억&lt;/li&gt;
&lt;li&gt;100억이라서 100% 시간초과 날 줄 알았는데 통과됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Another solution&lt;/h3&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;function solution(want, number, discount) {
  let count = 0;

  const isItemCountWrong = (discount10, index) =&amp;gt; {
    const filteredItemCount = discount10.filter((item) =&amp;gt; item === want[index]).length;
    const itemCount = number[index];
    return filteredItemCount !== itemCount;
  };

  for (let i = 0; i &amp;lt; discount.length - 9; i++) {
    const discount10 = discount.slice(i, i + 10);

    let flag = true;

    for (let j = 0; j &amp;lt; want.length; j++) {
      if (isItemCountWrong(discount10, j)) {
        flag = false;
        break;
      }
    }
    if (flag) count += 1;
  }

  return count;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;discount 배열을 slice하여 10개 뽑아냄&lt;/li&gt;
&lt;li&gt;want 배열을 순회하는데, 이때 slice에 filter 메서드를 적용하여 number에 명시된 숫자만큼 slice에 물건이 존제하는지 체크한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 수량이 다르면 flag를 false로 변경하고, break를 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/160586&quot;&gt;대충 만든 자판&lt;/a&gt; (Level 1)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Problem Summary&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;keymap 배열에 있는 키 배열에 따라 target을 완성해야 하는데, 이때 target을 만들기 위한 최소 키 누르는 횟수&lt;/li&gt;
&lt;li&gt;목표 문자열을 작성할 수 없다면 -1 리턴&lt;/li&gt;
&lt;li&gt;특정 target의 알파벳을 누르고 난 후의 위치가 유지되는 것은 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Solution&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;function solution(keymap, targets) {
  const map = new Map();

  keymap.forEach((v) =&amp;gt; {
    for (let i = 0; i &amp;lt; v.length; i++) {
      const keyName = v[i];
      const count = i + 1;
			// 현재 count가 이미 저장된 카운트보다 적다면 적은 값으로 교체해준다.
      if (!map.has(keyName) || map.get(keyName) &amp;gt; count) {
        map.set(keyName, count);
      }
    }
  });

  return targets.reduce((acc, target) =&amp;gt; {
    let totalCount = 0;
    for (const el of target) {
      if (!map.get(el)) {
        totalCount = -1;
        break;
      }
      totalCount += map.get(el);
    }
    acc.push(totalCount);
    return acc;
  }, []);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 알파벳을 입력하기 위한 최소 횟수가 명시된 Map을 생성한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;{알파벳: 입력 횟수(인덱스의 최솟값 + 1)}&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;target 배열을 순회하면서 totalCount를 누적해준다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 map에 없는 요소라면 totalCount를 -1로 변경 후 break하여 바로 값을 배열에 push한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Time Complexity&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;O(N) : 선형 시간 복잡도&lt;/li&gt;
&lt;li&gt;O(K * L)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;K: keymap 배열의 원소 수 (최대 100)&lt;/li&gt;
&lt;li&gt;L: targets 배열의 원소 수 (최대 100)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;keymap.forEach + for loop
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간 복잡도 keymap 배열 원소 수 * keymap 배열의 원소 길이&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;targets.reduce + for loop
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;target 배열 원소 수 * target 배열의 원소 길이&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/172927&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;광물 캐기&lt;/a&gt; (Level 2)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Problem Summary&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3가지의 곡괭이가 있고, 3가지의 광물을 캘 수 있는데 각각 피로도가 다르다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다이아, 철, 돌 순으로 피로도가 적게 소모된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;5개의 광물을 캔 후에는 더 이상 사용 불가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Solution&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;곡괭이의 수만큼만 5개씩 광물 쌍을 만들어준다.&lt;/li&gt;
&lt;li&gt;각 쌍을 돌면서 다이아로 캤을 때의 피로도/철로 캤을 때의 피로도/돌로 캤을 때의 피로도 합을 구함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;피로도는 다이아로 캤을 때 가장 적을 거고, 돌로 캤을 때 가장 클 것&lt;/li&gt;
&lt;li&gt;피로도의 합으로 정렬을 할 것이기 때문에 피로도의 총합도 구해 준다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;{ sum: 0, dia: 0, iron: 0, stone: 0 }&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;피로도의 합이 큰 것이 뒤로 오도록 stack을 정렬해준다.&lt;/li&gt;
&lt;li&gt;stack을 탐색하며 pop 하면서 가능하면 다이아 곡괭이부터 소진한다.&lt;/li&gt;
&lt;li&gt;곡괭이를 소진하며 피로도를 answer에 누적한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;function solution(picks, minerals) {
  let answer = 0;

  const picksLength = picks.reduce((a, b) =&amp;gt; a + b, 0) * 5; // 총 캘 수 있는 광물의 수
  const maxMinerals = Math.min(picksLength, minerals.length);

  // 캘 수 있는 광물만 딱 오기 때문에 queue를 쓰지 않아도 될 것
  const stack = [];
  // 5개씩 각 광물 개수 분석
  for (let i = 0; i &amp;lt; maxMinerals; i += 5) {
    const obj = { sum: 0, dia: 0, iron: 0, stone: 0 };
    for (let j = i; j &amp;lt; Math.min(i + 5, maxMinerals); j++) {
      if (minerals[j] === 'diamond') {
        obj.dia += 1;
        obj.iron += 5;
        obj.stone += 25;
      }

      if (minerals[j] === 'iron') {
        obj.dia += 1;
        obj.iron += 1;
        obj.stone += 5;
      }

      if (minerals[j] === 'stone') {
        obj.dia += 1;
        obj.iron += 1;
        obj.stone += 1;
      }
    }
    obj.sum += obj.dia + obj.iron + obj.stone;
    stack.push(obj);
  }

  stack.sort((a, b) =&amp;gt; a.sum - b.sum); // 피로도 큰 것이 뒤로 오도록 정렬

  const pickMap = { dia: picks[0], iron: picks[1], stone: picks[2] };

  while (stack.length) {
    const { dia, iron, stone } = stack.pop();
    if (pickMap.dia) {
      answer += dia;
      pickMap.dia -= 1;
      continue;
    }
    if (pickMap.iron) {
      answer += iron;
      pickMap.iron -= 1;
      continue;
    }
    if (pickMap.stone) {
      answer += stone;
      pickMap.stone -= 1;
    }
  }

  return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Time Complexity&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;O(n log n)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;minerals 배열을 5개씩 끊어서 분석 : 분석해야 하는 광물 개수는 minerals 배열 길이(n)에 비례 &amp;rarr; O(n)&lt;/li&gt;
&lt;li&gt;stack 정렬하는 시간 복잡도: O(n log n)&lt;/li&gt;
&lt;li&gt;stack에 요소를 push, pop하는 시간 복잡도: O(1 * n)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;</description>
      <category>Algorithms</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/376</guid>
      <comments>https://jaypedia.tistory.com/376#entry376comment</comments>
      <pubDate>Sun, 23 Apr 2023 00:36:59 +0900</pubDate>
    </item>
    <item>
      <title>팀 프로젝트에 꼭 필요한 Commit Convention: 이슈 번호와 커밋 타입으로 관리하기</title>
      <link>https://jaypedia.tistory.com/374</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wt3vU/btr0eKdjfn8/lLAAYPU1hiURuP17Eke1mk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wt3vU/btr0eKdjfn8/lLAAYPU1hiURuP17Eke1mk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wt3vU/btr0eKdjfn8/lLAAYPU1hiURuP17Eke1mk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWt3vU%2Fbtr0eKdjfn8%2FlLAAYPU1hiURuP17Eke1mk%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;820&quot; height=&quot;410&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Motivation&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2022년 10월부터 &lt;b&gt;Pullanner 프로젝트&lt;/b&gt;를 진행하면서, 프론트엔드 팀원과 함께 커밋 컨벤션을 정리해 보았다. 사실 작년 11월 24일에 완성했지만 팀 노션에만 저장해 두었다.&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;팀원들이 나 포함 8명이었기 때문에 꽤 많았고, 각자가 사용해 왔던 커밋 컨벤션들을 돌아가면서 말하게 되었다. 이때 나는 정리해뒀던 커밋 컨벤션을 팀원분들께 보여드렸고, 이것이 최종 선택이 되었다.&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UWAoH/btr0fKwQgj1/tKXzNX0GqFvtApcHZA7200/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UWAoH/btr0fKwQgj1/tKXzNX0GqFvtApcHZA7200/img.png&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;734&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.8348%; margin-right: 10px;&quot; data-widthpercent=&quot;48.4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UWAoH/btr0fKwQgj1/tKXzNX0GqFvtApcHZA7200/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUWAoH%2Fbtr0fKwQgj1%2FtKXzNX0GqFvtApcHZA7200%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;1528&quot; height=&quot;734&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw4ooq/btr0gCL0zBl/GIkhKwIyNSk6yT5O1qsVYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw4ooq/btr0gCL0zBl/GIkhKwIyNSk6yT5O1qsVYK/img.png&quot; data-origin-width=&quot;1314&quot; data-origin-height=&quot;592&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.0024%;&quot; data-widthpercent=&quot;51.6&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw4ooq/btr0gCL0zBl/GIkhKwIyNSk6yT5O1qsVYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw4ooq%2Fbtr0gCL0zBl%2FGIkhKwIyNSk6yT5O1qsVYK%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;1314&quot; height=&quot;592&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;  Commit Type and Description&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;1248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/evp5Xa/btr0hexmhJ0/pSwTrse82Tv0UvyTTge4B0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/evp5Xa/btr0hexmhJ0/pSwTrse82Tv0UvyTTge4B0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/evp5Xa/btr0hexmhJ0/pSwTrse82Tv0UvyTTge4B0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fevp5Xa%2Fbtr0hexmhJ0%2FpSwTrse82Tv0UvyTTge4B0%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;1842&quot; height=&quot;1248&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;1248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 쓰는 타입 위주로 정리해 보았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 커밋에 타입을 명시해 두면, &lt;b&gt;코드의 변경 이유를 커밋 메시지의 타입만 보고도 캐치할 수 있기 때문&lt;/b&gt;에 매우 효율적이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 커밋 메시지의 Feat만 보고도 '이 커밋은 새로운 기능을 추가한 코드가 있겠구나'라고 바로 파악할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 명확한 정보를 통해 코드의 변경 이유를 파악하는 시간을 줄일 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Commit message &amp;amp; Description&lt;/h2&gt;
&lt;pre class=&quot;dos&quot;&gt;&lt;code&gt;[#Issue Number] Type: commit title

Description&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;이렇게 이슈를 명시함으로써 이 커밋이 어떤 이슈와 연관되어 있는지 쉽게 파악할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀원들이 이 이슈와 관련된 코드의 변경 사항을 쉽게 파악할 수 있고, 이는 작업의 효율성이 좋아지는 길이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Commit Rules&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;커밋을 하는 단위는&lt;/b&gt; &lt;b&gt;커밋 메시지 한 줄로 설명할 수 있는 행동&lt;/b&gt;이어야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커밋을 잘게 쪼개자 ―&lt;/b&gt; 커다란 커밋보단 너무 상세하더라도 작은 커밋이 더 낫다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;복잡한 커밋보단 간단한 커밋&lt;/b&gt; &lt;b&gt;―&lt;/b&gt; 한 커밋의 한 파일에서 2가지 액션이 들어가는 순간, 해당 커밋은 복잡한 커밋이 된다. (커밋의 type을 섞지 말자)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Reference&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jaeheon.kr/257&quot;&gt;커밋을 잘게 쪼개자 - 커밋은 언제 하는 것이 가장 좋을까?&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming/Git</category>
      <author>Millie</author>
      <guid isPermaLink="true">https://jaypedia.tistory.com/374</guid>
      <comments>https://jaypedia.tistory.com/374#entry374comment</comments>
      <pubDate>Wed, 22 Feb 2023 09:45:36 +0900</pubDate>
    </item>
  </channel>
</rss>