<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>web study</title>
    <link>https://fromnowwon.tistory.com/</link>
    <description>About programming language, web, network, browser, coding test ...</description>
    <language>ko</language>
    <pubDate>Sun, 26 Jul 2026 04:57:43 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>fnow</managingEditor>
    <image>
      <title>web study</title>
      <url>https://tistory1.daumcdn.net/tistory/4381244/attach/5aa1987ec9214a7d866ae7ec32b6386c</url>
      <link>https://fromnowwon.tistory.com</link>
    </image>
    <item>
      <title>AWS SAA (Solutions Architect - Associate) 시험 정보</title>
      <link>https://fromnowwon.tistory.com/entry/AWS-SAA</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 컴퓨팅이 점점 더 보편화되면서, AWS는 기업과 개발자들에게 필수적인 기술로 자리 잡고 있습니다. 그중에서도 AWS Certified Solutions Architect - Associate(SAA) 자격증은 AWS 아키텍처 설계 및 배포 능력을 공식적으로 인증하는 가장 인기 있는 시험 중 하나입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 자격증은 AWS 기반의 고가용성, 보안, 비용 최적화 및 성능 최적화 아키텍처를 설계하는 데 필요한 핵심 지식을 검증합니다. 따라서 클라우드 엔지니어, 솔루션 아키텍트, DevOps 엔지니어뿐만 아니라 AWS에 대한 이해도를 높이고 싶은 개발자에게도 유용한 자격증입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS는 지속적으로 시험 내용을 업데이트하지만, SAA-C03(&lt;b&gt;2022년 8월 도입&lt;/b&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;1. 시험 개요&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시험 코드: SAA-C03&lt;/li&gt;
&lt;li&gt;시험 형식: 객관식 (단일 선택 및 복수 선택)&lt;/li&gt;
&lt;li&gt;시험 시간: 130분&lt;/li&gt;
&lt;li&gt;합격 점수: 100~1,000점 범위에서 최소 720점 이상&lt;/li&gt;
&lt;li&gt;문제 개수: 총 65문제 (15문제는 시험 연구 목적으로 채점 제외)&lt;/li&gt;
&lt;li&gt;시험 비용: $150 (재응시 바우처 및 연습 시험: $20)&lt;/li&gt;
&lt;li&gt;언어: 한국어, 영어, 일본어 등 지원&lt;/li&gt;
&lt;li&gt;유효 기간: 3년&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;2. 시험 범위 (도메인별 비중)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 설계 원칙 적용 (Design Secure Architectures) - 30%&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS 보안 모범 사례(암호화, IAM, 네트워크 보안)&lt;/li&gt;
&lt;li&gt;보안 서비스 활용(AWS KMS, IAM, Security Hub 등)&lt;/li&gt;
&lt;li&gt;보안 정책 및 컴플라이언스 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 탄력적 아키텍처 설계 (Design Resilient Architectures) - 26%&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다중 가용 영역(AZ) 및 리전 설계&lt;/li&gt;
&lt;li&gt;고가용성 및 내결함성 아키텍처 구성&lt;/li&gt;
&lt;li&gt;자동 확장 및 복구 전략(ELB, Auto Scaling, Route 53)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 고성능 아키텍처 설계 (Design High-Perfoming Architectures) - 24%&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적절한 스토리지 솔루션 선택(S3, EBS, EFS, FSx)&lt;/li&gt;
&lt;li&gt;네트워크 성능 최적화(CloudFront, Global Accelerator)&lt;/li&gt;
&lt;li&gt;데이터베이스 성능 최적화(RDS, Aurora, DynamoDB, ElastiCache)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 비용 최적화 아키텍처 설계 (Design Cost-Optimized Architectures) - 20%&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적절한 요금제 선택(예약 인스턴스, Savings Plans)&lt;/li&gt;
&lt;li&gt;서버리스 및 컨테이너 비용 절감 전략(Lambda, ECS, Fargate)&lt;/li&gt;
&lt;li&gt;비용 분석 도구 활용(Cost Explorer, AWS Budgets)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 시험 준비 방법&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS 공식 자료 활용: AWS Skill Builder, 무료 연습 문제&lt;/li&gt;
&lt;li&gt;백서 및 문서 참고: Well-Architected Framework, AWS 모범 사례&lt;/li&gt;
&lt;li&gt;모의시험 응시: Udemy, Whizlabs, Tutorials Dojo 등 활용&lt;/li&gt;
&lt;li&gt;실습 환경 구축: AWS 프리 티어 이용하여 실습&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AWS</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/223</guid>
      <comments>https://fromnowwon.tistory.com/entry/AWS-SAA#entry223comment</comments>
      <pubDate>Fri, 31 Jan 2025 15:04:56 +0900</pubDate>
    </item>
    <item>
      <title>2024 비전공자 SQLD 3주 독학 합격 / 공부 방법 공유</title>
      <link>https://fromnowwon.tistory.com/entry/sqld</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;주니어 개발자로 일하고 있는데, 컴퓨터공학 등의 관련 전공이 아니다. 때문에 관련 지식 공부가 필요하다고 느껴 사이버대학에 편입하였다. 졸업하기 위해서는 IT 관련 자격증이 필요하다. 정보처리기사는 이미 취득했기 때문에 어떤 걸 취득할까 하다가 SQLD로 정했다. 실무에서 DB 전문가가 아니더라도 DB를 조작해서 테스트하는 일이 꽤 자주 있었다. 그리고 요즘은 사무직도 DB는 기본적으로 공부한다고 하더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024년 5월 25일 제53회 시험을 3주 앞두고 공부하기로 했다.&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;SQLD 과목&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출제 과목을 정리하는 건 기본 중 기본. 주관식이 사라지고 과목이 일부 변경되었으니, 과목도 반드시 체크해둘 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 71.9767%; height: 108px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 27.6468%; height: 19px;&quot;&gt;&lt;b&gt;주요 항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.3299%; height: 19px;&quot;&gt;&lt;b&gt;세부 항목&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 27.6468%; height: 38px;&quot; rowspan=&quot;2&quot;&gt;과목1. 데이터 모델링의 이해&lt;/td&gt;
&lt;td style=&quot;width: 44.3299%; height: 19px;&quot;&gt;제1장. 데이터 모델링의 이해&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 44.3299%; height: 19px;&quot;&gt;제2장. 데이터 모델과 SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 27.6468%; height: 51px;&quot; rowspan=&quot;3&quot;&gt;과목2. SQL 기본 및 활용&lt;/td&gt;
&lt;td style=&quot;width: 44.3299%; height: 17px;&quot;&gt;제1장. SQL 기본&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 44.3299%; height: 17px;&quot;&gt;제2장. SQL 활용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 44.3299%; height: 17px;&quot;&gt;제3장. 관리 구문&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;SQLD 3주 독학 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음부터 요약집으로 공부한다면 무슨 내용인지도 모를 뿐더러 합격선과 멀어질 것이다. 아래와 같은 과정으로 공부한다면, 합격은 거저먹기다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;공부 순서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념 강의 &amp;rarr; 강의 들으며 노션에 개념 정리 &amp;rarr; 노랭이 1 회독 &amp;rarr; 주요 개념 강의 &amp;rarr; 강의 내용 노션에 추가/수정 &amp;rarr; 노랭이 2 회독 &amp;rarr; 최신 기출 강의 &amp;rarr; 노랭이 3 회독 &amp;rarr; SQLD 최종 정리 강의 &amp;rarr; 요약집&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상세 내용과 강의 추천&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 모든 범위를 훑는 개념 강의를 듣는다.&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완전히 이해한다가 보다는 이런 내용이 나오는구나, 하면서 전체를 훑는다고 생각한다. 중간이 끊기 보다는 한 번에 듣는 걸 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;홍쌤의 데이터랩&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 1과목&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/QB_GYdHUHmA?si=KVytJaZsX3AHNPM-&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/QB_GYdHUHmA?si=KVytJaZsX3AHNPM-&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2과목 (1)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/_f_WZYuNr7A?si=fyTV-dcHrOZF481H&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/_f_WZYuNr7A?si=fyTV-dcHrOZF481H&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2과목 (2)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/EXx6fjxycSY?si=GvBL3Djh1AmRENZ2&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/EXx6fjxycSY?si=GvBL3Djh1AmRENZ2&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 개념 강의를 들으면서 노션에 개념 정리하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념 강의를 듣기만 하는 게 아니고, 노션같은 곳에 내용을 직접 정리한다. 나는 영상에 나오는 내용을 모두 노션에 받아 적으면서 들었다. 노션 정리의 장점은 키워드 검색이 가능하다는 점이다. 자신이 정리한 개념서는 공부할 때 진짜 도움 많이 된다. 아래는 개념 강의를 들으며 정리한 노션 개념서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-06-17 오후 3.16.40.png&quot; data-origin-width=&quot;1974&quot; data-origin-height=&quot;1284&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqjJT4/btsH0VJSK8m/JBUM7d68Zo1cwjjkx3KJ0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqjJT4/btsH0VJSK8m/JBUM7d68Zo1cwjjkx3KJ0k/img.png&quot; data-alt=&quot;노션에 정리한 SQLD 개념서&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqjJT4/btsH0VJSK8m/JBUM7d68Zo1cwjjkx3KJ0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqjJT4%2FbtsH0VJSK8m%2FJBUM7d68Zo1cwjjkx3KJ0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1974&quot; height=&quot;1284&quot; data-filename=&quot;스크린샷 2024-06-17 오후 3.16.40.png&quot; data-origin-width=&quot;1974&quot; data-origin-height=&quot;1284&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;노션에 정리한 SQLD 개념서&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 노랭이 1 회독&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답안지 보면서 '답'에 체크한다. 처음엔 뭔 소리야? 하고 저절로 입에서 튀어나올 텐데 그런 부분은 체크만 해두고 넘어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1718603495101&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;books.book&quot; data-og-title=&quot;SQL 자격검정 실전문제&quot; data-og-description=&quot;SQL 자격검정 실전문제&quot; data-og-host=&quot;www.aladin.co.kr&quot; data-og-source-url=&quot;http://aladin.kr/p/IQ6Rt&quot; data-og-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=332583104&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/f08uK/hyWleOVmix/iP7wjY3K9nvgEH8T2jcMik/img.jpg?width=500&amp;amp;height=678&amp;amp;face=0_0_500_678,https://scrap.kakaocdn.net/dn/czGhjo/hyWlg6Z4zg/ioZkZqNwIPlm55Tt8YrYkK/img.jpg?width=500&amp;amp;height=678&amp;amp;face=0_0_500_678&quot;&gt;&lt;a href=&quot;http://aladin.kr/p/IQ6Rt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://aladin.kr/p/IQ6Rt&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/f08uK/hyWleOVmix/iP7wjY3K9nvgEH8T2jcMik/img.jpg?width=500&amp;amp;height=678&amp;amp;face=0_0_500_678,https://scrap.kakaocdn.net/dn/czGhjo/hyWlg6Z4zg/ioZkZqNwIPlm55Tt8YrYkK/img.jpg?width=500&amp;amp;height=678&amp;amp;face=0_0_500_678');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SQL 자격검정 실전문제&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SQL 자격검정 실전문제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.aladin.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 주요 개념 강의&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 회독이 끝나면 자주 나오는 주제와 이해가 안 되는 주제에 대한 족집게 강의를 찾아본다. 그러면 이해가 쏙쏙 되면서 눈이 트일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 쏭즈 캠퍼스 SQLD 강의가 아주 많이 도움 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쏭즈캠퍼스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- WINDOW 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/2ec7S5tlGSI?si=VbAjsaFG2e07tVxa&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/2ec7S5tlGSI?si=VbAjsaFG2e07tVxa&lt;/a&gt;&lt;/p&gt;
&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;- GROUP 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/pXq_iWt704c?si=5Furey0oOGiWoJ1I&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/pXq_iWt704c?si=5Furey0oOGiWoJ1I&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 계층형 질의&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/JxyMJNX24LY?si=F3c2sYpj9UVdbxWt&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/JxyMJNX24LY?si=F3c2sYpj9UVdbxWt&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 위 채널에 있는 개념 강의는 무조건 듣는 게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 주요 개념 강의를 보고 나서 노션에 정리했던 개념에 추가/수정한다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 개념 강의를 보고 나면 수정하거나 추가해야 할 부분이 보인다. 바로 정리해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 노랭이 2 회독&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답안지가 친절하지 않기 때문에 아직도 이해가 안 되는 개념들은 강의를 다시 찾아본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. 기출 강의 듣기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기출을 혼자 열심히 풀기보다는 강의를 보면서 같이 푸는 걸 추천한다. 신유형도 정리해 주니 아주 좋은 강의!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;홍쌤의 데이터랩&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 기출 문제 풀이&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/5fTVqNUE5sg?si=kb1SjPqcG72I9B35&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/5fTVqNUE5sg?si=kb1SjPqcG72I9B35&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;7. 노랭이 3 회독&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 답을 체크하면서 넘어가는 속도가 빨라진다. 이때에도 이해 안 되는 부분은 개념 강의를 다시 돌려본다. 그리고 자주 나오거나 이해 안되는 문제는 여러 번 풀어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;8. SQLD 최종 정리 강의 듣기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 버전은 아니지만 내가 잘 이해하고 있는지 체크해 볼 수 있다. 범위가 아닌 부분은 과감히 스킵하고, 1.5배속으로 듣는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;김강민SQLP&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- SQLD 최종 정리 강의&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://youtu.be/PC3ypt_VGWI?si=Q9qxFBP2M_-1IX8h&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/PC3ypt_VGWI?si=Q9qxFBP2M_-1IX8h&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;9. 요약집으로 머릿속 개념 정리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약집은 이때 봐야 한다. 처음에 요약집을 봤을 때와 이 때 봤을 때 느낌은 차원이 다르다. 머릿속 개념들이 정리가 되는 느낌이 든다. 아래 카페에서 다운로드한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 전문가 포럼&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1718603516472&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;자격증 기출문제 등 학습자료 및 사이트 안내(2023.1.8.)&quot; data-og-description=&quot;[ (ADsP) 데이터분석 준전문가 요약('22.05.02.) ]* 요약1 : https://cafe.naver.com/sqlpd/29856* 요약2 : https://caf...&quot; data-og-host=&quot;cafe.naver.com&quot; data-og-source-url=&quot;https://cafe.naver.com/sqlpd/12755&quot; data-og-url=&quot;https://cafe.naver.com/sqlpd/12755&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d3t3Pz/hyWoOHNUpJ/LBQMZu8XJi2t5Vx0GSxKZK/img.png?width=270&amp;amp;height=270&amp;amp;face=0_0_270_270&quot;&gt;&lt;a href=&quot;https://cafe.naver.com/sqlpd/12755&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cafe.naver.com/sqlpd/12755&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d3t3Pz/hyWoOHNUpJ/LBQMZu8XJi2t5Vx0GSxKZK/img.png?width=270&amp;amp;height=270&amp;amp;face=0_0_270_270');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;자격증 기출문제 등 학습자료 및 사이트 안내(2023.1.8.)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[ (ADsP) 데이터분석 준전문가 요약('22.05.02.) ]* 요약1 : https://cafe.naver.com/sqlpd/29856* 요약2 : https://caf...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cafe.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;10. 시험 당일&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험장에는 요약집을 챙겨간다. 이때 요약집이 아직도 이해가 안 된다면 공부가 부족하다고 판단하면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시험 결과&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1과목 만점이고, 2과목에서 66점을 받아 총점 86점으로 합격했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;sqld시험점수결과.png&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEkrtr/btsH1jQ4s87/Y9LXqEiBrpEIlwhmosKjq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEkrtr/btsH1jQ4s87/Y9LXqEiBrpEIlwhmosKjq1/img.png&quot; data-alt=&quot;SQLD 독학 합격 점수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEkrtr/btsH1jQ4s87/Y9LXqEiBrpEIlwhmosKjq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEkrtr%2FbtsH1jQ4s87%2FY9LXqEiBrpEIlwhmosKjq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1088&quot; height=&quot;648&quot; data-filename=&quot;sqld시험점수결과.png&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SQLD 독학 합격 점수&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;팁과 느낀 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 비전공자라면 자만하지 말고 개념 강의를 꼭 들을 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 체감상 노랭이보다 쉽게 출제되었기 때문에 노랭이만으로 충분하다고 생각한다. (노랭이 3회독 이상 필수)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 처음부터 요약집을 보지 말자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주관식은 사라졌지만 주관식 기출문제를 풀어보는 건 추천&lt;/p&gt;
&lt;figure id=&quot;og_1718603435120&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[SQLD] 45 ~ 49회 기출문제 주관식 모음 ( 총 32문제/정답 )&quot; data-og-description=&quot;  SQLD 45 ~ 49회 기출문제 단답형 모음 문제 1. 45회 단답형 1 (1과목). 업무에서 필요로 하는 인스턴스로 관리하고자 하는 의미상 더 이상 분리 되지 않는 최소의 데이터 단위는? (노랭이 1과목 14번&quot; data-og-host=&quot;yunamom.tistory.com&quot; data-og-source-url=&quot;https://yunamom.tistory.com/355&quot; data-og-url=&quot;https://yunamom.tistory.com/355&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/zStOs/hyWoKSV26I/ycpdpg7xxTlloqt14XZvy1/img.png?width=696&amp;amp;height=696&amp;amp;face=0_0_696_696,https://scrap.kakaocdn.net/dn/tMo2a/hyWlay1hM2/NHe7DQ2KyKhK6vzHPlPink/img.png?width=696&amp;amp;height=696&amp;amp;face=0_0_696_696,https://scrap.kakaocdn.net/dn/df8bbL/hyWoMwrGK5/wBXBLcZssZKLmrNM1p1ibK/img.png?width=1698&amp;amp;height=1214&amp;amp;face=0_0_1698_1214&quot;&gt;&lt;a href=&quot;https://yunamom.tistory.com/355&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://yunamom.tistory.com/355&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/zStOs/hyWoKSV26I/ycpdpg7xxTlloqt14XZvy1/img.png?width=696&amp;amp;height=696&amp;amp;face=0_0_696_696,https://scrap.kakaocdn.net/dn/tMo2a/hyWlay1hM2/NHe7DQ2KyKhK6vzHPlPink/img.png?width=696&amp;amp;height=696&amp;amp;face=0_0_696_696,https://scrap.kakaocdn.net/dn/df8bbL/hyWoMwrGK5/wBXBLcZssZKLmrNM1p1ibK/img.png?width=1698&amp;amp;height=1214&amp;amp;face=0_0_1698_1214');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[SQLD] 45 ~ 49회 기출문제 주관식 모음 ( 총 32문제/정답 )&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  SQLD 45 ~ 49회 기출문제 단답형 모음 문제 1. 45회 단답형 1 (1과목). 업무에서 필요로 하는 인스턴스로 관리하고자 하는 의미상 더 이상 분리 되지 않는 최소의 데이터 단위는? (노랭이 1과목 14번&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;yunamom.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- PIVOT에 중점을 두지 않았는데, PIVOT 문제가 출제되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>ETC.</category>
      <category>SQLD</category>
      <category>sqld 강의</category>
      <category>개발자</category>
      <category>공부 방법</category>
      <category>독학</category>
      <category>자격증</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/222</guid>
      <comments>https://fromnowwon.tistory.com/entry/sqld#entry222comment</comments>
      <pubDate>Mon, 17 Jun 2024 15:27:40 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘-JS, Python] 백준 1253번: 좋다 (투 포인터)</title>
      <link>https://fromnowwon.tistory.com/entry/baekjoon-1253-js-python</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수 중에서 어떤 수가 다른 수 두 개의 합으로 나타낼 수 있다면 그 수를 &quot;좋다(GOOD)&quot;고 한다. N개의 수가 주어지면 그 중에서 좋은 수의 개수는 몇 개인지 출력하라. 수의 위치가 다르면 값이 같아도 다른 수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JavaScript&lt;/h3&gt;
&lt;pre id=&quot;code_1710730077816&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const input = fs.readFileSync('input.txt').toString().trim().split('\n');

const N = parseInt(input[0]);
const A = input[1].split(' ').map(Number);

let Result = 0;

for (let k = 0; k &amp;lt; N; k++) {
    let find = A[k];
    let i = 0;
    let j = N - 1;

    while (i &amp;lt; j) {
        if (A[i] + A[j] === find) {
            if (i !== k &amp;amp;&amp;amp; j !== k) {
                Result++;
                break;
            } else if (i === k) {
                i++;
            } else if (j === k) {
                j--;
            }
        } else if (A[i] + A[j] &amp;lt; find) {
            i++;
        } else {
            j--;
        }
    }
}

console.log(Result);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Python&lt;/h3&gt;
&lt;pre id=&quot;code_1710731329230&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
input = sys.stdin.readline

N = int(input())
Result = 0
A = list(map(int, input().split()))
A.sort()

for k in range(N):
    find = A[k]
    i = 0
    j = N - 1

    while i &amp;lt; j:
        if A[i] + A[j] == find:
            if (i != k and j != k):
                Result += 1
                break
            elif (i == k):
                i += 1
            elif (j == k):
                j -= 1
        elif A[i] + A[j] &amp;lt; find:
            i += 1
        else:
            j -= 1

print(Result)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Data Structure &amp;amp; Algorithm</category>
      <category>백준</category>
      <category>알고리즘</category>
      <category>자바스크립트</category>
      <category>투 포인터</category>
      <category>파이썬</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/221</guid>
      <comments>https://fromnowwon.tistory.com/entry/baekjoon-1253-js-python#entry221comment</comments>
      <pubDate>Mon, 18 Mar 2024 12:12:39 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘-JS, Python] 백준 2018번: 연속된 자연수의 합 (투 포인터)</title>
      <link>https://fromnowwon.tistory.com/entry/baekjoon-2018-js-python</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어떠한 자연수 N은, 몇 개의 연속된 자연수의 합으로 나타낼 수 있다. 당신은 어떤 자연수 N(1 &amp;le; N &amp;le; 10,000,000)에 대해서, 이 N을 몇 개의 연속된 자연수의 합으로 나타내는 가지수를 알고 싶어한다. 이때, 사용하는 자연수는 N이하여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 15를 나타내는 방법은 15, 7+8, 4+5+6, 1+2+3+4+5의 4가지가 있다. 반면에 10을 나타내는 방법은 10, 1+2+3+4의 2가지가 있다. N을 입력받아 가지수를 출력하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JavaScript&lt;/h3&gt;
&lt;pre id=&quot;code_1710674565784&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const n = parseInt(require('fs').readFileSync(&quot;input.txt&quot;).toString().trim(), 10);

let count = 1; // 가장 마지막 수만 뽑는 경우의 수를 미리 넣고 시작
let start_index = 1; // 각 인덱스에 담긴 값이 1로 시작하므로 같이 하기 위함
let end_index = 1; // 각 인덱스에 담긴 값이 1로 시작하므로 같이 하기 위함
let sum = 1; // 각 인덱스에 담긴 값이 1로 시작하므로 초기 sum은 1

while (end_index !== n) {
	if (sum === n) {
    	count++; // 카운트 증가 먼저 한 후,
        end_index++; // end index 증가
        sum += end_index; // sum에 새로운 end_index 더함
    } else if (sum &amp;gt; n) {
    	sum -= start_index; // 현재 start_index를 먼저 빼주고,
        start_index++; // start_index 증가
    } else {
    	end_index++;
        sum += end_index;
    }
}

console.log(count);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Python&lt;/h3&gt;
&lt;pre id=&quot;code_1710674831818&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = int(input())
start_index = 1
end_index = 1
sum = 1
count = 1

while end_index != n:
    if sum == n:
        count += 1
        end_index += 1
        sum += end_index
    elif sum &amp;gt; n:
        sum -= start_index
        start_index += 1
    else:
        end_index += 1
        sum += end_index
        
print(count)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Data Structure &amp;amp; Algorithm</category>
      <category>백준 2018</category>
      <category>수들의 합</category>
      <category>알고리즘</category>
      <category>자바스크립트</category>
      <category>투포인터</category>
      <category>파이썬</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/220</guid>
      <comments>https://fromnowwon.tistory.com/entry/baekjoon-2018-js-python#entry220comment</comments>
      <pubDate>Sun, 17 Mar 2024 20:29:05 +0900</pubDate>
    </item>
    <item>
      <title>[React] Redux Toolkit에서 비동기 처리하기</title>
      <link>https://fromnowwon.tistory.com/entry/react-redux-toolkit-async-thunk</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기존 Redux에서는 middleware를 사용하여 비동기 처리를 해야 했다. 안 그래도 복잡한 코드가 더 복잡해져 유지보수가 까다로워진다. Redux Toolkit은 간결한 코드로 비동기 처리를 쉽게 할 수 있다.&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;Redux와 Redux toolkit 비동기 처리 비교&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 151px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Redux&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Redux Toolkit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;비동기 처리 도구&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Middleware&lt;br /&gt;- Redux Thunk&lt;br /&gt;- Redux Saga&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;createAsyncThunk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;액션 타입 정의&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;수동으로 정의해야 함&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;자동으로 생성됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;코드 구문&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Boilerplate 코드가 많음&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Redux보다 간결함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;설치 및 설정&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;별도의 미들웨어 설치 및 설정이 필요&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Redux Toolkit 패키지만 설치하면 따로 설치할 필요 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;액션 생성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;액션 생성자에서 직접 디스패치&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;createAsyncThunk에서 생성된 함수로 자동 디스패치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;상태 업데이트&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;수동으로 상태 업데이트&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;자동으로 상태 업데이트 및 액션 타입에 따라 리듀서가 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Redux에서 Redux Thunk를 사용한 예제&lt;/h3&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;const fetchUser = () =&amp;gt; {
  return async (dispatch) =&amp;gt; {
    dispatch({ type: 'FETCH_USER_REQUEST' });

    try {
      const response = await api.fetchUser();
      dispatch({ type: 'FETCH_USER_SUCCESS', payload: response.data });
    } catch (error) {
      dispatch({ type: 'FETCH_USER_FAILURE', payload: error.message });
    }
  };
};&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Redux Toolkit에서 createAsyncThunk를 사용한 예제&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// createAsyncThunk를 사용한 예제
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchUser = createAsyncThunk(
    'user/fetchUser', // 리듀서이름/비동기함수이름
    async (userId) =&amp;gt; {
      const response = await api.fetchUser(userId);
      return response.data;
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Redux Toolkit 주요 기능&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;createAsyncThunk&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 작업을 처리하는 데 사용되는 함수를 생성한다. createSlide 내부에서 사용하며, 해당 비동기 작업에 대한 액션을 생성한다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchUser = createAsyncThunk('user/fetchUser', async (userId) =&amp;gt; {
  const response = await api.fetchUser(userId);
  return response.data;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;pending, fullfilled, rejected&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;createAsyncThunk로 생성된 Thunk 함수의 세 가지 액션 상태다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pending: 비동기 작업 진행 중&lt;/li&gt;
&lt;li&gt;fullfiled: 비동기 작업 성공&lt;/li&gt;
&lt;li&gt;rejected: 비동기 작업 실패&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;builder.addCase(asyncUserFetch.pending, (state, action) =&amp;gt; {
  state.status = 'loading';
})
builder.addCase(asyncUserFetch.fulfilled, (state, action) =&amp;gt; {
  state.status = 'complete';
  state.userList = action.payload;
})
builder.addCase(asyncUserFetch.rejected, (state, action) =&amp;gt; {
  state.status = 'fail';
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드 예제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UserSlice.js&lt;/p&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;import { createAsyncThunk, createSlice } from &quot;@reduxjs/toolkit&quot;

// 비동기 action creator
export const asyncUserFetch = createAsyncThunk(
  'userSlice/asyncUserFetch',
  async () =&amp;gt; {
    const res = await fetch(&quot;https://jsonplaceholder.typicode.com/users&quot;)
    const data = await res.json();
    return data
  }
)

const userSlice = createSlice({
  name: 'userSlice',
  initialState: {
    userList: [],
    status: null, // status 초기값
  },
  extraReducers: (builder) =&amp;gt; {
    // 비동기 작업은 action creator를 자동으로 만들지 않기 때문에 extraReducers를 사용해서 action을 생성해야 한다.
    builder.addCase(asyncUserFetch.pending, (state) =&amp;gt; {
      state.status = 'Loading';
    })
    builder.addCase(asyncUserFetch.fulfilled, (state, action) =&amp;gt; {
      state.status = 'complete';
      state.userList = action.payload;
    })
    builder.addCase(asyncUserFetch.rejected, (state) =&amp;gt; {
      state.status = 'fail';
    })
  },
})

export default userSlice;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { configureStore } from &quot;@reduxjs/toolkit&quot;;
import userSlice from &quot;./userSlice&quot;;

// store 통합
const store = configureStore({
  reducer: {
    user: userSlice.reducer,
  }
})
export default store;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import './App.css';
import { Provider } from 'react-redux';
import UserList from './components/UserList';
import store from './store';

function App() {
  return (
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;div className=&quot;App&quot;&amp;gt;
        &amp;lt;UserList /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/Provider&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UserList.js&lt;/p&gt;
&lt;pre id=&quot;code_1707108498029&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useEffect } from 'react'
import { asyncUserFetch } from '../userSlice';
import { useDispatch, useSelector } from 'react-redux';

const UserList = () =&amp;gt; {
  const dispatch = useDispatch();
  const userList = useSelector(state =&amp;gt; state.user.userList);
  const status = useSelector(state =&amp;gt; state.user.status);

  useEffect(() =&amp;gt; {
    dispatch(asyncUserFetch());
  }, [dispatch]);
  
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;ul&amp;gt;
        {
          status === 'Loading' ? (
            &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;
          ) : userList &amp;amp;&amp;amp; userList.map(user =&amp;gt; (
            &amp;lt;li key={user.id}&amp;gt;
              &amp;lt;div&amp;gt;{user.name}&amp;lt;/div&amp;gt;
            &amp;lt;/li&amp;gt;
          ))
        }
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default UserList&lt;/code&gt;&lt;/pre&gt;</description>
      <category>React</category>
      <category>react</category>
      <category>redux toolkit</category>
      <category>리덕스 툴킷</category>
      <category>리액트</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/219</guid>
      <comments>https://fromnowwon.tistory.com/entry/react-redux-toolkit-async-thunk#entry219comment</comments>
      <pubDate>Mon, 5 Feb 2024 14:02:51 +0900</pubDate>
    </item>
    <item>
      <title>[React] redux-toolkit 사용 이유, redux와 비교</title>
      <link>https://fromnowwon.tistory.com/entry/React-redux-toolkit</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Redux toolkit은 Redux를 효율적으로 사용하기 위한 공식 라이브러리다. Redux를 사용하던 개발자들이 보다 쉽게 코드를 작성하고 유지보수할 수 있도록 해준다. Redux toolkit을 통해 Redux의 코드 복잡성을 줄이고, 보일러플레이트 코드(반복적인 코드)를 최소화하며, 개발자 경험을 향상할 수 있다.&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;왜 Redux Toolkit을 사용해야 하는가?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 간결한 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;createSlice&lt;/code&gt;와 &lt;code&gt;configureStore&lt;/code&gt;와 같은 간편한 함수들을 제공하여 보일러플레이트 코드를 최소화한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 불변성 유지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;createSlice&lt;/code&gt;는 내부적으로 Immer 라이브러리를 사용한다. Immer 라이브러리는 기존 객체를 직접적으로 수정해도 불변성을 유지될 수 있도록 해준다. Immer는 이전 상태를 변경하지 않고 새로운 상태를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기존 방식: 불변성 유지를 위해 새로운 객체 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt; function reducer(state = initialState, action) {
   switch(action.type) {
     case ADD:
       return {
         ...state, // 기존 상태 객체를 전개하여 새로운 객체 생성
         value: state.value + 1 // value 속성만 변경
       }
     case SUBTRACT:
       return {
         ...state,
         value: state.value - 1
       }
     default:
       return state;
   }
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Immer를 사용한 방식: 불변성 유지를 간단하게 처리&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1707097267881&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  reducers: {
    add: state =&amp;gt; {
      state.value += 1; // 상태를 직접 변경하여도 새로운 객체가 생성됨
    },
    subtract: (state, action) =&amp;gt; {
      state.value -= action.payload;
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 통합된 비동기 처리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;createAsyncThunk&lt;/code&gt;를 사용하여 비동기 작업을 쉽게 처리할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Redux DevTools 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux Toolkit도 Redux와 마찬가지로 Redux DevTools를 통해 디버깅할 수 있다.&lt;/p&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;Redux Toolkit 주요 기능과 장점&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;createSlice 함수: 리듀서와 액션을 통합적으로 정의할 수 있는 &lt;code&gt;createSlice&lt;/code&gt;함수를 제공한다.&lt;/li&gt;
&lt;li&gt;configureStore 함수: 스토어를 구성하는 데 사용되며, 여러 개의 리듀서를 효과적으로 결합하여 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;Immer 라이브러리: 불변성 유지를 보다 쉽게 할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;redux와 redux-toolkit 비교&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;redux 사용&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// App.js
import { Provider, useSelector, useDispatch } from 'react-redux';
import { createStore } from 'redux';

// action type
const ADD = 'ADD';
const SUBTRACT = 'SUBTRACT';

// reducer
const initialState = {
  value: 0
}

function reducer(state = initialState, action) {
  switch(action.type) {
    case ADD:
      return {
        ...state,
        value: state.value + 1
      }
    case SUBTRACT:
      return {
        ...state,
        value: state.value - 1
      }
    default:
      return state;
  }
}

// store
const store = createStore(reducer);

// counter component
function Counter() {
  const dispatch = useDispatch();
  const count = useSelector(state =&amp;gt; state.value);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch( { type: ADD })}&amp;gt;+&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch( { type: SUBTRACT })}&amp;gt;-&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

function App() {
  return (
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;div className=&quot;App&quot;&amp;gt;
        &amp;lt;Counter/&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/Provider&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;redux-toolkit으로 개선&lt;/h3&gt;
&lt;pre id=&quot;code_1707097198741&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// App.js
import { Provider, useSelector, useDispatch } from 'react-redux';
import { configureStore, createSlice } from '@reduxjs/toolkit';

// reducer와 action이 통합된 작은 store
const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  reducers: {
    add: state =&amp;gt; {
      state.value += 1;
    },
    subtract: (state, action) =&amp;gt; {
      state.value -= action.payload;
    }
  }
})

// store 통합
const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
  }
})

// counter component
function Counter() {
  const dispatch = useDispatch();
  const count = useSelector(state =&amp;gt; state.counter.value);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;
      {/* 방식1 */}
      &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'counter/add', payload: 3 })}&amp;gt;+&amp;lt;/button&amp;gt;
      {/* 방식2 */}
      &amp;lt;button onClick={() =&amp;gt; dispatch(counterSlice.actions.subtract(2))}&amp;gt;-&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

function App() {
  return (
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;div className=&quot;App&quot;&amp;gt;
        &amp;lt;Counter/&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/Provider&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>React</category>
      <category>react</category>
      <category>Redux</category>
      <category>Redux-toolkit</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/218</guid>
      <comments>https://fromnowwon.tistory.com/entry/React-redux-toolkit#entry218comment</comments>
      <pubDate>Mon, 5 Feb 2024 10:46:08 +0900</pubDate>
    </item>
    <item>
      <title>[React] 미들웨어 정리표</title>
      <link>https://fromnowwon.tistory.com/entry/react-middleware</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 미들웨어는 애플리케이션의 액션과 스토어 상태 간의 중간 단계로서 동작하는 소프트웨어다. 주로 Redux와 함께 사용되며, 액션을 처리하거나 상태를 변화시키기 전에 추가적인 작업을 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;미들웨어 정리표&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 150px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;미들웨어&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;redux-thunk&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;비동기 작업을 처리하고 액션 생성자에서 함수를 반환할 수 있게 해준다. 주로 비동기 작업을 다룰 때 사용된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;redux-saga&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;제너레이터 함수를 이용하여 복잡한 비동기 작업을 처리하는 미들웨어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;redux-logger&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;개발환경에서 스토어의 액션과 상태를 콘솔에 로깅하여 디버깅을 도와주는 미들웨어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;redux-persist&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;스토어의 상태를 지속적으로 유지하고, 로컬 스토리지 또는 다른 저장소에 상태를 저장할 수 있게 해준다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;redux-throttle&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;특정 액션에 대한 디스패치를 제어하여 쓸데없는 액션 호출을 방지할 수 있게 해주는 미들웨어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;redux-observable&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;RxJS를 기반으로 하는 미들웨어로, 비동기 작업을 처리하기 위해 Observables를 사용한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;redux-batched-actions&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;액션 디스패치를 배치 처리하여 성능을 최적화해주는 미들웨어&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미들웨어는 프로젝트의 요구 사항에 따라 다양하게 선택될 수 있다. 사용하고자 하는 미들웨어는 프로젝트의 특성과 필요에 따라 적절히 선택되어야 한다.&lt;/p&gt;</description>
      <category>React</category>
      <category>Middleware</category>
      <category>react</category>
      <category>리액트</category>
      <category>미들웨어</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/217</guid>
      <comments>https://fromnowwon.tistory.com/entry/react-middleware#entry217comment</comments>
      <pubDate>Sun, 4 Feb 2024 18:01:50 +0900</pubDate>
    </item>
    <item>
      <title>[React] redux-thunk로 비동기 동작 다루기 + 예제</title>
      <link>https://fromnowwon.tistory.com/entry/redux-thunk</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Redux Thunk는 미들웨어 중 하나로, 비동기 작업을 처리하고 액션을 디스패치할 수 있게 도와주는 라이브러리다. 리덕스는 동기적인 작업에 특화되어 있어서, 비동기 작업을 처리하기 위해서는 Thunk와 같은 미들웨어가 필요하다. 그 외에도 비동기 작업을 처리하는 미들웨어로 Redux Saga, Redux Observable 등이 있다.&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;동기적 액션 생성자와 Thunk를 사용한 비동기 액션 생성자 비교&lt;/h2&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;객체&amp;rsquo;를 반환&lt;/li&gt;
&lt;li&gt;반환 형식:&amp;nbsp;&lt;code&gt;{ type: '액션_타입', payload: '데이터' }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;동기적인 액션을 생성하는 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Thunk를 사용한 비동기 액션 생성자&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;함수&amp;rsquo;를 반환&lt;/li&gt;
&lt;li&gt;비동기 액션 함수는 &lt;code&gt;dispatch&lt;/code&gt;를 인자로 받음&lt;br /&gt;이를 통해 함수 내부에서 다른 액션을 디스패치할 수 있는 권한을 갖게 되는 것&lt;/li&gt;
&lt;li&gt;비동기 코드 실행 전, 실행 후 등 비동기 동작 전 후 상황에서 액션을 실행해야 할 때 디스패치를 사용&lt;/li&gt;
&lt;li&gt;비동기 액션 함수 내에서 비동기 작업을 수행하고, 필요에 따라 여러 액션을 디스패치할 수 있음&lt;/li&gt;
&lt;li&gt;반환 형식: &lt;code&gt;(dispatch) =&amp;gt; { /* 비동기 작업 수행 및 액션 디스패치 */ }&lt;/code&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;redux-thunk 설치와 코드 예제&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치&lt;/h3&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;npm install redux-thunk
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드 예제&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;github&lt;/b&gt;: &lt;a href=&quot;https://github.com/fromnowwon/redux-cafe-order-system&quot;&gt;https://github.com/fromnowwon/redux-cafe-order-system&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { createStore, applyMiddleware } from &quot;redux&quot;;
import rootReducer from &quot;./rootReducer&quot;;
import logger from &quot;redux-logger&quot;;
import { thunk } from &quot;redux-thunk&quot;;
import { composeWithDevTools } from &quot;redux-devtools-extension&quot;;

// 여러 middleware 배열로 관리
// thunk를 먼저 배치
const middleware = [thunk, logger];

// rootReducer를 사용하는 스토어 생성
const store = createStore(
    rootReducer,
    composeWithDevTools(applyMiddleware(...middleware))
);

export default store;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rootReducer.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { combineReducers } from &quot;redux&quot;;
import orderReducer from &quot;./order/reducer&quot;;
import customerReducer from &quot;./customer/reducer&quot;;

// 모든 리듀서 통합
const rootReducer = combineReducers({
    orders: orderReducer,
    customers: customerReducer,
});

export default rootReducer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reducer.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import {
    FETCH_CUSTOMER_REQUEST,
    FETCH_CUSTOMER_SUCCESS,
    FETCH_CUSTOMER_FAILURE,
} from &quot;./types&quot;;

const initialState = {
    items: [],
    loading: false,
    error: null,
};

const customerReducer = (state = initialState, action) =&amp;gt; {
    switch (action.type) {
        case FETCH_CUSTOMER_REQUEST:
            return {
                ...state,
                loading: true,
            };
        case FETCH_CUSTOMER_SUCCESS:
            return {
                ...state,
                items: action.payload,
                loading: false,
            };
        case FETCH_CUSTOMER_FAILURE:
            return {
                ...state,
                error: action.payload,
                loading: false,
            };
        default:
            return state;
    }
};

export default customerReducer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;actions.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import {
  FETCH_CUSTOMER_REQUEST,
  FETCH_CUSTOMER_SUCCESS,
  FETCH_CUSTOMER_FAILURE,
} from &quot;./types&quot;;

// 동기적인 액션 생성자: 데이터를 받아오는 요청이 시작됐음을 알리는 경우
export const fetchCustomerRequest = () =&amp;gt; {
  return {
    type: FETCH_CUSTOMER_REQUEST,
  };
};

// 동기적인 액션 생성자: 데이터를 성공적으로 받아온 경우
export const fetchCustomerSuccess = (customers) =&amp;gt; {
  return {
    type: FETCH_CUSTOMER_SUCCESS,
    payload: customers,
  };
};

// 동기적인 액션 생성자: 데이터를 받아오는 과정에서 에러가 발생한 경우
export const fetchCustomerFailure = (err) =&amp;gt; {
  return {
    type: FETCH_CUSTOMER_FAILURE,
    payload: err,
  };
};

// Thunk를 사용한 비동기 액션 생성자
export const fetchCustomer = () =&amp;gt; {
    // dispatch를 인자로 받는다
    return async (dispatch) =&amp;gt; {
        try {
            // 먼저 요청이 시작했음을 나타내는 액션 디스패치
            dispatch(fetchCustomerRequest());

            // 비동기 작업
            const response = await fetch(
                &quot;&amp;lt;https://jsonplaceholder.typicode.com/users&amp;gt;&quot;
            );
            const customers = await response.json();

            // 비동기 작업 완료 후 성공 시 액션 디스패치
            dispatch(fetchCustomerSuccess(customers));
        } catch (error) {
            // 비동기 작업 실패 시 액션 디스패치
            dispatch(fetchCustomerFailure(error.message));
        }
    };
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>React</category>
      <category>react</category>
      <category>Redux</category>
      <category>thunk</category>
      <category>비동기</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/216</guid>
      <comments>https://fromnowwon.tistory.com/entry/redux-thunk#entry216comment</comments>
      <pubDate>Sun, 4 Feb 2024 17:58:00 +0900</pubDate>
    </item>
    <item>
      <title>[Vanilla JavaScript] Redux 사용 예제</title>
      <link>https://fromnowwon.tistory.com/entry/Vanilla-JavaScript-Redux</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 자바스크립트 기반의 상태 관리 라이브러리다. 주로 React와 사용되지만 순수 자바스크립트, Angular, Vue에서도 사용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 상태를 예측할 수 있으며, 상태의 변경이 적은 방식에 중점을 두고 있다. 이러한 특징은 단일 페이지 애플리케이션(SPAs) 또는 자바스크립트 프레임워크 및 라이브러리와 잘 맞는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;React 예제&lt;/b&gt;: &lt;a href=&quot;https://fromnowwon.tistory.com/entry/react-redux&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://fromnowwon.tistory.com/entry/react-redux&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;Redux 설치와 코드 예제&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;github&lt;/b&gt;:&amp;nbsp;https://github.com/fromnowwon/redux-vanilla-cafe-order-syatem&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치&lt;/h3&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;npm install redux
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드 예제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;store.js: 스토어 (주문목록 저장소)&lt;/li&gt;
&lt;li&gt;actions.js: 액션 (요구사항)&lt;/li&gt;
&lt;li&gt;reducers.js: 리듀서 (점원)&lt;/li&gt;
&lt;li&gt;view.js: 주문 목록 화면&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store.js&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux 미들웨어는 액션을 통한 상태 변경이 이뤄지기 전 중간 단계에서 동작하는 코드다. 액션과 리듀서 사이에서 추가적인 작업을 수행하거나 변경할 수 있다. 미들웨어를 사용하는 이유는 비동기 작업, 로깅, 유효성 검사, 라우팅 등 다양하다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const redux = require('redux'); // Redux 라이브러리 가져오기
const reduxLogger = require('redux-logger'); // Redux 상태 변화를 로깅하기 위한 라이브러리
const { createStore, applyMiddleware, combineReducers } = redux;
const { createLogger } = reduxLogger;
const { orderReducer } = require('./reducers');

// 미들웨어 생성 및 루트 리듀서 설정
const logger = createLogger(); // 로깅 미들웨어를 생성 (상태 변화 기록)
const rootReducer = combineReducers({
  order: orderReducer,
}); // combineReducer를 사용하면 여러 개의 리듀서를 합쳐서 사용할 수 있다.

// orderReducer를 사용하는 스토어 생성
// =&amp;gt; 담당 점원의 주문 목록 생성
const store = createStore(rootReducer, applyMiddleware(logger));

module.exports = store;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;actions.js&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 액션 타입 정의
// =&amp;gt; 요구 사항 정의
const ADD_ORDER = 'ADD_ORDER';
const CANCEL_ORDER = 'CANCEL_ORDER';

// 액션 생성 함수 정의
// =&amp;gt; 요구 사항에 대한 동작
const addOrder = (item, quantity) =&amp;gt; {
  return {
    type: ADD_ORDER,
    payload: {
      item,
      quantity,
    },
  };
};

const cancelOrder = (orderId) =&amp;gt; {
  return {
    type: CANCEL_ORDER,
    payload: {
      orderId,
    },
  };
};

module.exports = {
  addOrder,
  cancelOrder,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reducers.js&lt;/p&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;// 초기 상태 정의
// =&amp;gt; 주문이 없는 상태
const initialStateOrders = [];

// 리듀서 함수 정의
// =&amp;gt; 점원의 역할 정의
const orderReducer = (state = initialStateOrders, action) =&amp;gt; {
  switch (action.type) {
    case 'ADD_ORDER':
      return [
        ...state,
        {
          id: state.length + 1,
          item: action.payload.item,
          quantity: action.payload.quantity,
        },
      ];
    case 'CANCEL_ORDER':
      return state.filter(order =&amp;gt; order.id !== action.payload.orderId);
    default:
      return state;
  }
};

module.exports = {
  orderReducer,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;view.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// view.js
const store = require('./store');
const { addOrder, cancelOrder } = require('./actions');

// store.subscribe(() =&amp;gt; {
//   console.log('현재 주문 목록: ', store.getState());
// });

// 주문 실행
store.dispatch(addOrder('아메리카노', 2));
store.dispatch(cancelOrder(1)); // 주문 ID 넘기기
store.dispatch(addOrder('카라멜 마키아또', 3));
store.dispatch(cancelOrder(2));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행&lt;/h3&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;node view.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reduxLogger라는 미들웨어를 사용했기 때문에, 콘솔 창에서 state의 변화를 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;redux-vanilla-js.jpg&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ca3jC0/btsEkdF7Cme/JSSvqo5uQFNvx6qyUdurN0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ca3jC0/btsEkdF7Cme/JSSvqo5uQFNvx6qyUdurN0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ca3jC0/btsEkdF7Cme/JSSvqo5uQFNvx6qyUdurN0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fca3jC0%2FbtsEkdF7Cme%2FJSSvqo5uQFNvx6qyUdurN0%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;734&quot; height=&quot;273&quot; data-filename=&quot;redux-vanilla-js.jpg&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>JavaScript</category>
      <category>Redux</category>
      <category>state</category>
      <category>리덕스</category>
      <category>상태 관리</category>
      <category>자바스크립트</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/215</guid>
      <comments>https://fromnowwon.tistory.com/entry/Vanilla-JavaScript-Redux#entry215comment</comments>
      <pubDate>Fri, 2 Feb 2024 10:48:51 +0900</pubDate>
    </item>
    <item>
      <title>[React] Redux 사용 이유와 예제</title>
      <link>https://fromnowwon.tistory.com/entry/react-redux</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 JavaScript 애플리케이션의 상태 관리 라이브러리이다. React에서 Redux를 사용하는 주된 이유는 상태 관리의 효율성과 예측 가능성을 높이기 위함이다. React 차체에서도 컴포넌트 state를 통한 상태 관리가 가능하지만, 복잡한 상태 관리가 필요한 대규모 애플리케이션에서는 Redux와 같은 전역 상태 관리 방식을 도입한다.&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;Redux 사용 이유&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;중앙 집중식 상태 관리와 단일 출처&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 상태를 하나의 스토어에 저장한다. 때문에 한 곳에서 모든 상태 관리가 이루어진다. 이는 데이터가 어디서 오는지 명확하게 파악할 수 있게 하며, 데이터의 일관성을 유지할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예측 가능성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 상태의 변화를 예측 가능한 방식으로 다룬다. 상태는 불변성을 유지하면서 액션에 의해 변경되므로, 특정 액션이나 이벤트에 대한 상태 변화를 예측하기 쉽다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상태 불변성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 상태를 불변 객체로 다루기를 권장한다. 상태를 직접 변경하는 것이 아니라 새로운 상태를 반환하는 방식으로 상태를 관리하게끔 한다. 불변성을 유지하면 상태 변화를 추적하고 이전 상태와 현재 상태 간의 차이를 쉽게 계산할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;디버깅 용이성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 미들웨어와 개발자 도구를 통해 상태 변화를 추적할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;미들웨어 지원&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미들웨어를 통해 액션 디스패치 중간에 특정 작업을 수행할 수 있다. 이를 통해 비동기 작업, 로깅, 라우팅 등 다양한 기능을 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;Redux 주요 용어 (카페 주문 시스템 비유)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스토어 (Store)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 주문 목록이나 주문 관련 모든 데이터를 포함하는 곳&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리듀서 (Reducer)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 종류의 주문을 처리하는 점원. 예를 들어, 아메리카노를 만드는 점원, 라떼를 만드는 점원 등으로 설명할 수 있다. 주문이 들어오면 해당 주문에 따라 레시피에 맞게 음료를 제조하고, 주문 상태를 업데이트한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;디스패치 (Dispatch)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문 요청을 적절한 주문 처리 직원에게 보내는 행위&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;액션 (Action)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문 요청. &quot;아메리카노 주문&quot; 또는 &quot;라떼 주문 취소&quot;와 같이 주문에 대한 요청이 액션에 해당한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;불변성 (Immutability)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 주문을 수정하는 대신에 새로운 목록을 생성하여 업데이트&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구독(Subscribe)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문 상태 변경을 감지하여 화면에 자동으로 반영하는 행위&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;미들웨어(Middleware)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문 처리 전에 특정 동작이나 조건을 확인하는 단계. 예를 들어, 주문을 받기 전에 할인 쿠폰이 적용되었는지 확인하는 행위.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;액션 크리에이터(Action Creator)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 주문 요청에 대한 액션 객체를 생성. 예를 들어 메뉴판에 나열된 음료 중에서 특정 음료를 선택하면 그 음료에 대한 주문이 요청된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Redux 데이터 흐름&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;View &amp;rArr; Dispatch &amp;rArr; (Middleware) &amp;rArr; Reducer &amp;rArr; New State! &amp;rArr; Store &amp;rArr; Components&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카페 주문 상황 &amp;rArr; 아메리카노 주문할게요! &amp;rArr; (할인쿠폰 있나요?) &amp;rArr; 직원이 주문 내역 업데이트 &amp;rArr; 새로운 주문 내역 생성! &amp;rArr; 주문 대기 목록 업데이트 &amp;rArr; 주문 대기 화면에 표시&lt;/p&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;Redux 설치와 코드 예제&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;github&lt;/b&gt;: &lt;a href=&quot;https://github.com/fromnowwon/redux-cafe-order-system&quot;&gt;https://github.com/fromnowwon/redux-cafe-order-system&lt;/a&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Vanilla JS 예제&lt;/b&gt;: &lt;a href=&quot;https://fromnowwon.tistory.com/entry/Vanilla-JavaScript-Redux&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://fromnowwon.tistory.com/entry/Vanilla-JavaScript-Redux&lt;/a&gt;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치&lt;/h3&gt;
&lt;pre id=&quot;code_1706771296082&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install redux react-redux&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;코드 예제 (리팩토링 ver.)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에 더 가까운 버전으로 리팩토링 하였다. (기존 버전은 아래에)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;변경 사항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 구조 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;components, redux로 나누어 정리하였고, redux 내에서도 기능에 따라 폴더를 나누었다.&lt;/p&gt;
&lt;pre id=&quot;code_1706851422927&quot; class=&quot;stylus&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;/redux-cafe-order-system
├── src
│   ├── components
│   │   ├── CafeOrderSystem.js
│   └── redux
│       ├── order
│       │   ├── actions.js
│       │   ├── reducer.js
│       │   └── types.js
│       ├── index.js
│       ├── rootReducer.js
│       └── store.js
└── package.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. reducer 통합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 reducer를 rootReducer로 통합하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 미들웨어 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미들웨어인 redux-logger를 사용해서 state 변화를 추적할 수 있도록 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 주문 총 개수 출력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 개념을 실생활과 연결하면 이해하기 쉽다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;store: 스토어 (주문목록)&lt;/li&gt;
&lt;li&gt;actions: 액션 (요구사항)&lt;/li&gt;
&lt;li&gt;reducers: 리듀서 (점원)&lt;/li&gt;
&lt;li&gt;CafeOrderSystem: 주문 화면 컴포넌트&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;components/CafeOrderSystem.js&lt;/p&gt;
&lt;pre id=&quot;code_1706851844995&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addOrder, cancelOrder } from '../redux';

const CafeOrderSystem = (props) =&amp;gt; {
  const dispatch = useDispatch();
  const orderList = useSelector(state =&amp;gt; state.orders.orderList);

  const handleAddOrder = (item) =&amp;gt; {
    dispatch(addOrder(item, 1));
  };

  const handleCancelOrder = (orderId) =&amp;gt; {
    dispatch(cancelOrder(orderId));
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h3&amp;gt;음료를 선택해주세요&amp;lt;/h3&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; handleAddOrder('아메리카노')}&amp;gt;아메리카노&amp;lt;/button&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; handleAddOrder('카페 라떼')}&amp;gt;카페 라떼&amp;lt;/button&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; handleAddOrder('카라멜 마키아또')}&amp;gt;카라멜 마키아또&amp;lt;/button&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; handleAddOrder('바닐라 라떼')}&amp;gt;바닐라 라떼&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h3&amp;gt;주문 리스트&amp;lt;/h3&amp;gt;
        &amp;lt;span&amp;gt;(총 {orderList.length}잔)&amp;lt;/span&amp;gt;
        &amp;lt;ul&amp;gt;
          {orderList.map(order =&amp;gt; (
            &amp;lt;li key={order.id}&amp;gt;
              {order.item} (수량: {order.quantity})
              &amp;lt;button onClick={() =&amp;gt; handleCancelOrder(order.id)}&amp;gt;주문 취소&amp;lt;/button&amp;gt;
            &amp;lt;/li&amp;gt;
          ))}
        &amp;lt;/ul&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default CafeOrderSystem;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux/index.js&lt;/p&gt;
&lt;pre id=&quot;code_1706851913753&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 모든 액션 통합하여 내보내기
export { addOrder, cancelOrder } from './order/actions';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux/store.js&lt;/p&gt;
&lt;pre id=&quot;code_1706851921883&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createStore, applyMiddleware } from 'redux';
import rootReducer from './rootReducer';
import logger from 'redux-logger';

// 여러 middleware 배열로 관리
const middleware = [logger];

// rootReducer를 사용하는 스토어 생성
const store = createStore(rootReducer, applyMiddleware(...middleware));

export default store;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux/rootReducer.js&lt;/p&gt;
&lt;pre id=&quot;code_1706851933055&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { combineReducers } from &quot;redux&quot;;
import orderReducer from &quot;./order/reducer&quot;;

// 모든 리듀서 통합
const rootReducer = combineReducers({
  orders: orderReducer,
})

export default rootReducer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux/order/reducer.js&lt;/p&gt;
&lt;pre id=&quot;code_1706851949857&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ADD_ORDER, CANCEL_ORDER } from './types';

// 초기 상태 정의
// =&amp;gt; 주문이 없는 상태
const initialState = {
  orderList: [],
};

// 리듀서 함수 정의
// =&amp;gt; 점원의 역할 정의
const orderReducer = (state = initialState, action) =&amp;gt; {
  switch (action.type) {
    case ADD_ORDER:
      console.log('ADD_ORDER', state)
      return {
        ...state,
        orderList: [
          ...state.orderList,
          {
            id: state.orderList.length + 1,
            item: action.payload.item,
            quantity: action.payload.quantity,
          },
        ],
      };
    case CANCEL_ORDER:
      return {
        ...state,
        orderList: state.orderList.filter(order =&amp;gt; order.id !== action.payload.orderId),
      };
    default:
      return state;
  }
};

export default orderReducer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux/order/actions.js&lt;/p&gt;
&lt;pre id=&quot;code_1706851963105&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ADD_ORDER, CANCEL_ORDER } from &quot;./types&quot;;

// 액션 생성 함수 정의
// =&amp;gt; 요구 사항에 대한 동작
export const addOrder = (item, quantity) =&amp;gt; ({
  type: ADD_ORDER,
  payload: { item, quantity },
});

export const cancelOrder = (orderId) =&amp;gt; ({
  type: CANCEL_ORDER,
  payload: { orderId },
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux/order/types.js&lt;/p&gt;
&lt;pre id=&quot;code_1706851975651&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 액션 타입 정의
// =&amp;gt; 요구 사항 정의
export const ADD_ORDER = 'ADD_ORDER';
export const CANCEL_ORDER = 'CANCEL_ORDER';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드 예제 (기존 ver.)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프로젝트 구조&lt;/h4&gt;
&lt;pre id=&quot;code_1706851602631&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;redux-cafe-order-system
├── src
│   ├── actions.js
│   ├── reducer.js
│   ├── store.js
│   └── CafeOrderSystem.js
└── package.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { createStore } from 'redux';
import orderReducer from './reducers';

// orderReducer를 사용하는 스토어 생성
// =&amp;gt; 담당 점원의 주문 목록 생성
const store = createStore(orderReducer);

export default store;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;actions.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 액션 타입 정의
// =&amp;gt; 요구 사항 정의
export const ADD_ORDER = 'ADD_ORDER';
export const CANCEL_ORDER = 'CANCEL_ORDER';

// 액션 생성 함수 정의
// =&amp;gt; 요구 사항에 대한 동작
export const addOrder = (item, quantity) =&amp;gt; ({
  type: ADD_ORDER,
  payload: { item, quantity },
});

export const cancelOrder = (orderId) =&amp;gt; ({
  type: CANCEL_ORDER,
  payload: { orderId },
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reducers.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { ADD_ORDER, CANCEL_ORDER } from './actions';

// 초기 상태 정의
// =&amp;gt; 주문이 없는 상태
const initialState = {
  orders: [],
};

// 리듀서 함수 정의
// =&amp;gt; 점원의 역할 정의
const orderReducer = (state = initialState, action) =&amp;gt; {
  switch (action.type) {
    case ADD_ORDER:
      return {
        ...state,
        orders: [
          ...state.orders,
          {
            id: state.orders.length + 1,
            item: action.payload.item,
            quantity: action.payload.quantity,
          },
        ],
      };
    case CANCEL_ORDER:
      return {
        ...state,
        orders: state.orders.filter(order =&amp;gt; order.id !== action.payload.orderId),
      };
    default:
      return state;
  }
};

export default orderReducer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CafeOrderSystem.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addOrder, cancelOrder } from './actions';

const CafeOrderSystem = () =&amp;gt; {
  const dispatch = useDispatch();
  const orders = useSelector(state =&amp;gt; state.orders);

  const handleAddOrder = (item) =&amp;gt; {
    dispatch(addOrder(item, 1));
  };

  const handleCancelOrder = (orderId) =&amp;gt; {
    dispatch(cancelOrder(orderId));
  };

  return (
    // 주문 화면
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h3&amp;gt;음료를 선택해주세요&amp;lt;/h3&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; handleAddOrder('아메리카노')}&amp;gt;아메리카노&amp;lt;/button&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; handleAddOrder('카페 라떼')}&amp;gt;카페 라떼&amp;lt;/button&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; handleAddOrder('카라멜 마키아또')}&amp;gt;카라멜 마키아또&amp;lt;/button&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; handleAddOrder('바닐라 라떼')}&amp;gt;바닐라 라떼&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h3&amp;gt;주문 리스트&amp;lt;/h3&amp;gt;
        &amp;lt;ul&amp;gt;
          {orders.map(order =&amp;gt; (
            &amp;lt;li key={order.id}&amp;gt;
              {order.item} (수량: {order.quantity})
              &amp;lt;button onClick={() =&amp;gt; handleCancelOrder(order.id)}&amp;gt;주문 취소&amp;lt;/button&amp;gt;
            &amp;lt;/li&amp;gt;
          ))}
        &amp;lt;/ul&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default CafeOrderSystem;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에 Redux를 도입하면 복잡한 애플리케이션의 상태 관리를 효율적으로 할 수 있다. Redux를 사용할지 여부는 프로젝트의 규모와 복잡도, 상태 관리의 필요성 등에 따라 결정하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>React</category>
      <category>react</category>
      <category>Redux</category>
      <category>state</category>
      <category>리덕스</category>
      <category>전역 상태 관리</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/214</guid>
      <comments>https://fromnowwon.tistory.com/entry/react-redux#entry214comment</comments>
      <pubDate>Thu, 1 Feb 2024 16:10:27 +0900</pubDate>
    </item>
    <item>
      <title>[React] 상태 관리 방법 정리표 (전역/로컬)</title>
      <link>https://fromnowwon.tistory.com/entry/react-state-management</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리액트의 상태 관리 방법에는 여러 가지가 있다. 효과적인 상태 관리는 매우 중요하다. 상태 관리의 핵심은 어떻게 애플리케이션의 데이터를 구조화하고 관리하는가에 달려있다. 크게는 로컬 상태 관리와 전역 상태 관리를 기준으로 나눌 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;리액트 상태 관리 방법 정리표&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 258px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;관리 방법&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;로컬/전역&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;주요 특징&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;주요 사용 시점&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;useState Hook&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;로컬&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 함수형 컴포넌트에서 상태를 관리하는 데 사용됨&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;작은 규모의 컴포넌트 또는 컴포넌트 간 통신에 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;useReducer Hook&lt;/span&gt; &lt;span data-token-index=&quot;0&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;로컬&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;- 복잡한 상태 로직을 다룰 때, 이전 상태와 액션을 활용하여 상태를 업데이트&lt;br /&gt;- 컴포넌트 로직을 분리하고 예측 가능한 상태 관리 가능&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;복잡한 상태 로직이나 컴포넌트 간 통신이 많은 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;Context API&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 컴포넌트 트리 전체에서 데이터를 전달할 수 있는 React 내장 API&lt;br /&gt;- Provider 및 Consumer로 구성&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;대규모 애플리케이션 또는 전역 상태 관리가 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;Redux&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 상태 관리 라이브러리로 단일 스토어에서 상태를 효과적으로 관리&lt;br /&gt;- Actions, Reducers, Store로 구성&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;대규모 애플리케이션 또는 복잡한 상태 로직이 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;MobX&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 상태 관리 라이브러리로 반응형 상태를 쉽게 관리 가능&lt;br /&gt;- Observables, Actions, Reactions로 구성&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;단순하고 반응적인 상태 관리가 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;Recoil&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 상태를 전역적으로 관리하는 데 사용되는 상태 관리 라이브러리&lt;br /&gt;- Atom, Selector, RecoilRoot로 구성&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;대규모 애플리케이션 또는 복잡한 상태 로직이 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;Zustand&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;로컬/전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 작은 규모의 애플리케이션 또는 로컬 상태 관리에 유용한 상태 관리 라이브러리&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;작은 규모의 애플리케이션 또는 로컬 상태 관리가 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;React Query&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 서버 데이터 또는 비동기 작업에 특화된 상태 관리 라이브러리&lt;br /&gt;- Queries, Mutations, QueryClient로 구성&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;비동기 작업이 많은 경우 또는 서버 데이터 관리가 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;SWR (Stale-While-Revalidate)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 서버 데이터 및 상태를 효과적으로 관리하는 데 사용되는 리액트 훅 라이브러리&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;서버 데이터에 대한 최적화된 상태 관리가 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt; &lt;span data-token-index=&quot;0&quot;&gt;Apollo Client&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- GraphQL을 사용하는 애플리케이션에서 데이터를 효과적으로 관리하는 클라이언트 라이브러리&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;GraphQL을 사용하고 있는 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt; &lt;span data-token-index=&quot;0&quot;&gt;Easy Peasy&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- Redux 기반의 상태 관리 라이브러리로 간단한 API 및 적은 설정으로 상태를 관리할 수 있음&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Redux 기반으로 간편한 상태 관리가 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt; &lt;span data-token-index=&quot;0&quot;&gt;XState&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 상태 머신(State Machine)을 활용하여 상태 관리하는 JavaScript 라이브러리&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;상태가 복잡하거나 특정한 순서에 따라 상태를 변경해야 하는 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt; &lt;span data-token-index=&quot;0&quot;&gt;Jotai&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;로컬/전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 리액트 애플리케이션에서 상태를 관리하기 위한 간단하고 직관적인 라이브러리&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;적은 코드로 상태를 효과적으로 관리하고자 할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt; &lt;span data-token-index=&quot;0&quot;&gt;Valtio&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;로컬/전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 리액트 상태를 관리하기 위한 간단하고 효율적인 라이브러리&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;작은 규모의 프로젝트 또는 로컬 상태 관리가 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;Overmind&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;전역&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 간결하고 직관적인 구문으로 상태 관리를 할 수 있는 상태 관리 라이브러리&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;대규모 애플리케이션 또는 간단하게 상태를 관리하고자 할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주요 방식 설명&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Context API와 Hooks&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React의 Context API와 Hooks를 사용한 로컬 상태 관리는 여전히 많은 프로젝트에서 사용되고 있다. 특히 함수형 컴포넌트와 Hooks를 적극적으로 활용하는 트렌드가 이어지면서 useState와 useContext를 조합하여 간단한 상태 관리를 구현하는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Redux 및 Redux Toolkit&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 대규모 애플리케이션에서의 상태 관리에 많이 사용된다. 최근에는 Redux Toolkit이라는 Redux를 편리하게 사용할 수 있는 도구가 소개되었는데, 코드를 단순화하고 개발자 경험을 개선하는 데 도움을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;React Query 및 SWR&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 데이터 요청 및 상태 관리를 위한 라이브러리로는 React Query와 SWR이 주목받고 있다. 특히 서버와의 데이터 통신 및 상태 업데이트에 특화되어 있어, GraphQL이나 RESTful API와 효과적으로 통합된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Zustand와 Recoil&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zustand와 Recoil 같은 라이브러리는 비교적 가벼우면서도 효율적인 전역 상태 관리를 제공한다. 특히 Zustand는 간단한 API와 작은 번들 크기로 주목받고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GraphQL과 Apollo Client&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL을 사용하는 프로젝트에서는 Apollo Client와 함께 GraphQL 쿼리 및 상태 관리를 위한 솔루션으로 사용되고 있다.&lt;/p&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;그 외에도 다양한 상태 관리 라이브러리들도 사용되고 있다. 예를 들어, XState는 상태 머신을 기반으로 한 상태 관리를 제공하며, Overmind는 간결한 구문과 직관적인 API로 주목을 받고 있다.&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;</description>
      <category>React</category>
      <category>state</category>
      <category>리액트</category>
      <category>상태 관리</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/213</guid>
      <comments>https://fromnowwon.tistory.com/entry/react-state-management#entry213comment</comments>
      <pubDate>Wed, 31 Jan 2024 14:59:14 +0900</pubDate>
    </item>
    <item>
      <title>[React] useReducer (useState와 비교)</title>
      <link>https://fromnowwon.tistory.com/entry/React-useReducer-useState</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;useReducer는 React의 훅 중 하나로, useState처럼 state를 생성하고 관리할 수 있게 해주는 도구이다. useReducer는 여러 개의 하위 값을 포함하는 복잡한 state를 다뤄야 할 때 사용한다. useState와 비교하며 useReducer를 왜 사용하는지부터 우선 알아보자.&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;useState VS. useReducer&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useState는 간단한 상태 관리에 주로 사용된다. 하지만 상태가 복잡하고 여러 개의 하위 값이 포함된 경우, 상태를 업데이트하는 로직이 복잡해질 수 있다. 이때, useReducer를 사용하면 복잡한 상태 로직을 더 효율적으로 다룰 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 상태란, 여러 하위 값을 포함하거나 여러 상태 간의 관계가 복잡한 경우를 의미한다. 예를 들어, 사용자의 프로필 정보가 여러 부분으로 나누어져 있고, 각 부분마다 별도의 상태가 필요한 경우가 있다. 아래 예시를 살펴보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;복잡한 상태를 useState로 관리하는 경우&lt;/h3&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;// useState
const [name, setName] = useState('');
const [age, setAge] = useState(0);
const [email, setEmail] = useState('');

// 업데이트 로직
const handleNameChange = (newName) =&amp;gt; {
  setName(newName);
};

const handleAgeChange = (newAge) =&amp;gt; {
  setAge(newAge);
};

const handleEmailChange = (newEmail) =&amp;gt; {
  setEmail(newEmail);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;handleNameChange, handleAgeChange, handleEmailChange 함수는 각각 하나의 상태를 업데이트 하는 역할을 한다. 이렇게 되면 각 필드에 대한 업데이트 로직이 분리되어 있어서 상태 관리 코드가 복잡해진다. 특히 상태의 수가 많아지면 코드의 양이 급격하게 증가할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;복잡한 상태를 useReducer로 관리하는 경우&lt;/h3&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;// useReducer
const profileReducer = (state, action) =&amp;gt; {
  switch (action.type) {
    case 'SET_NAME':
      return { ...state, name: action.payload };
    case 'SET_AGE':
      return { ...state, age: action.payload };
    case 'SET_EMAIL':
      return { ...state, email: action.payload };
    default:
      return state;
  }
};

const [profile, dispatch] = useReducer(profileReducer, {
  name: '',
  age: 0,
  email: '',
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 useReducr를 사용하면 여러 가지 상태 업데이트 로직이 하나의 reducer 함수 안에 모여 있어 코드가 더 구조적이고 간결해진다. 이를 통해 관련된 업데이트 로직을 한 곳에서 효과적으로 관리할 수 있다.&lt;/p&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;useReducer 이해와 사용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useReducer의 주요 개념은 State, Reducer, Dispatch, Action으로 나눌 수 있다. 이해하기 쉽도록 카페 주문 시스템을 예시로 살펴보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;state: 현재 주문 목록&lt;/li&gt;
&lt;li&gt;Reducer: 카페 점원&lt;/li&gt;
&lt;li&gt;Dispatch: 카페 손님의 요구 행위&lt;/li&gt;
&lt;li&gt;Action: 요구 사항&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;손님의 요구 행위(요구 사항) &amp;rArr; 카페 점원(기존 목록, 요구 사항) &amp;rArr; 새로운 주문 목록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;dispatch(action) &amp;rArr; reducer(state, action) &amp;rArr; return new state!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카페 손님은 주문 목록을 직접 업데이트 하지 않는다. 카페 점원이 요구 사항에 따라 주문 목록을 업데이트한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;dispatcher는 state를 직접 업데이트하지 않는다. reducer가 action에 따라 state를 업데이트한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드 구현&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;github&lt;/b&gt;: &lt;a href=&quot;https://github.com/fromnowwon/useReducer-cafe-order-system&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/fromnowwon/useReducer-cafe-order-system&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CafeOrderSystem.js&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import React, { useReducer, useState } from &quot;react&quot;;
import { orderReducer } from &quot;./reducer&quot;;

const CafeOrderSystem = () =&amp;gt; {
	// orderReducer라는 reducer를 사용하고, 초기 상태는 빈 배열로 설정하겠다는 의미
	// useReducer는 state와 dispatch를 담은 배열을 반환한다
	// 반환된 현재 state와 dispatch를 [orders, dispatch]에 담는 것
	const [orders, dispatch] = useReducer(orderReducer, []);
	// 업데이트된 주문을 저장하는 state
	const [newOrder, setNewOrder] = useState({ drink: &quot;&quot;, size: &quot;&quot;, price: &quot;&quot; });

	// 주문 추가하는 함수
	const addOrder = () =&amp;gt; {
		// input 입력 값이 비어있지 않은 경우에만 추가
		if (
			newOrder.drink.trim() !== &quot;&quot; &amp;amp;&amp;amp;
			newOrder.size.trim() !== &quot;&quot; &amp;amp;&amp;amp;
			newOrder.price.trim() !== &quot;&quot;
		) {
			// 손님요구(요구사항): Dispatch(Action)
			dispatch({ type: &quot;ADD_ORDER&quot;, ...newOrder });
			// 주문을 추가한 후에는 입력값 초기화
			setNewOrder({ drink: &quot;&quot;, size: &quot;&quot;, price: &quot;&quot; });
		}
	};

	// 주문 취소 함수
	const cancelOrder = (id) =&amp;gt; {
		// 손님요구(요구사항): Dispatch(Action)
		dispatch({ type: &quot;CANCEL_ORDER&quot;, id });
	};

	return (
		&amp;lt;div&amp;gt;
			&amp;lt;h1&amp;gt;Cafe Order System&amp;lt;/h1&amp;gt;
			{/* 새로운 주문 정보 입력 */}
			&amp;lt;input
				type=&quot;text&quot;
				placeholder=&quot;음료&quot;
				value={newOrder.drink}
				onChange={(e) =&amp;gt; setNewOrder({ ...newOrder, drink: e.target.value })}
			/&amp;gt;
			&amp;lt;input
				type=&quot;text&quot;
				placeholder=&quot;사이즈&quot;
				value={newOrder.size}
				onChange={(e) =&amp;gt; setNewOrder({ ...newOrder, size: e.target.value })}
			/&amp;gt;
			&amp;lt;input
				type=&quot;number&quot;
				placeholder=&quot;가격&quot;
				step=&quot;10&quot;
				value={newOrder.price}
				onChange={(e) =&amp;gt; setNewOrder({ ...newOrder, price: e.target.value })}
			/&amp;gt;
			&amp;lt;button onClick={addOrder}&amp;gt;주문 추가&amp;lt;/button&amp;gt;
			{/* 주문 목록 표시 */}
			&amp;lt;ul&amp;gt;
				{orders.map((order) =&amp;gt; (
					&amp;lt;li key={order.id}&amp;gt;
						{order.drink} ({order.size}) - {order.price}원
						&amp;lt;button onClick={() =&amp;gt; cancelOrder(order.id)}&amp;gt;주문 취소&amp;lt;/button&amp;gt;
					&amp;lt;/li&amp;gt;
				))}
			&amp;lt;/ul&amp;gt;
		&amp;lt;/div&amp;gt;
	);
};

export default CafeOrderSystem;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reducer.js&lt;/p&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;// Action Type 정의 (요구사항 종류)
const ACTION_TYPES = {
	ADD_ORDER: &quot;ADD_ORDER&quot;,
	CANCEL_ORDER: &quot;CANCEL_ORDER&quot;,
}

// 점원(현재주문목록, 요구사항)
export const orderReducer = (state, action) =&amp;gt; {
	switch (action.type) {
		case ACTION_TYPES.ADD_ORDER:
			return [
				...state,
				{
					id: Date.now(),
					drink: action.drink,
					size: action.size,
					price: action.price,
				},
			];
		case ACTION_TYPES.CANCEL_ORDER:
			return state.filter((order) =&amp;gt; order.id !== action.id);
		default:
			return state;
	}
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CafeOrderSystem 컴포넌트에서는 여러 주문을 다룬다. 주문 추가와 주문 취소와 같이 다양한 액션(행위)에 대한 상태 업데이트 로직이 있다. useReducer는 이러한 복잡한 상태 로직을 더 구조적으로 관리할 수 있게 해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useReducer를 사용하면 상태 관리 로직이 한 군데에서 이뤄지기 때문에, 여러 컴포넌트에서 동일한 상태 및 상태 업데이트 로직을 공유할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 위 코드에서 useReducer 대신 useState를 사용하여 상태 관리를 구현하면 어떤 문제가 발생할까?&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import React, { useState } from &quot;react&quot;;

const CafeOrderSystem = () =&amp;gt; {
  const [orders, setOrders] = useState([]);
  const [newOrder, setNewOrder] = useState({ drink: &quot;&quot;, size: &quot;&quot;, price: &quot;&quot; });

  const addOrder = () =&amp;gt; {
    if (
      newOrder.drink.trim() !== &quot;&quot; &amp;amp;&amp;amp;
      newOrder.size.trim() !== &quot;&quot; &amp;amp;&amp;amp;
      newOrder.price.trim() !== &quot;&quot;
    ) {
      // 주문 추가 시 기존 상태를 변경하는 방식
      setOrders([...orders, newOrder]);
      setNewOrder({ drink: &quot;&quot;, size: &quot;&quot;, price: &quot;&quot; });
    }
  };

  const cancelOrder = (id) =&amp;gt; {
    // 주문 취소 시 기존 상태를 변경하는 방식
    setOrders(orders.filter(order =&amp;gt; order.id !== id));
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Cafe Order System&amp;lt;/h1&amp;gt;
      {/* 입력 폼 */}
      {/* ... (이하 생략) ... */}
      &amp;lt;button onClick={addOrder}&amp;gt;주문 추가&amp;lt;/button&amp;gt;
      {/* 주문 목록 표시 */}
      &amp;lt;ul&amp;gt;
        {orders.map((order) =&amp;gt; (
          &amp;lt;li key={order.id}&amp;gt;
            {order.drink} ({order.size}) - {order.price}원
            &amp;lt;button onClick={() =&amp;gt; cancelOrder(order.id)}&amp;gt;주문 취소&amp;lt;/button&amp;gt;
          &amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default CafeOrderSystem;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조가 간단한 경우 별다른 차이를 못 느낄 수 있다. 하지만 액션과 업데이트 로직이 분산되어 있기 때문에 복잡한 구조일 경우 코드가 길어지고 가독성이 감소할 수 있다. useReducer를 사용하면 이러한 로직을 하나의 리듀서 함수에서 관리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론: 상태 관리가 복잡한 경우 useState보다는 useReducer가 코드의 일관성과 유지보수성을 높을 수 있다.&lt;/p&gt;</description>
      <category>React</category>
      <category>react</category>
      <category>useReducer</category>
      <category>useState</category>
      <category>리액트</category>
      <category>상태 관리</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/212</guid>
      <comments>https://fromnowwon.tistory.com/entry/React-useReducer-useState#entry212comment</comments>
      <pubDate>Wed, 31 Jan 2024 13:59:28 +0900</pubDate>
    </item>
    <item>
      <title>[React] 자식 컴포넌트에서 부모 컴포넌트 상태 변경하기</title>
      <link>https://fromnowwon.tistory.com/entry/react-parent-component-state-update</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;React에서 컴포넌트 간의 효율적인 상태 관리는 중요한 요소 중 하나다. 특히 자식 컴포넌트에서 부모 컴포넌트의 상태를 업데이트하는 상황이 종종 있다. 자식 컴포넌트에서 부모 컴포넌트의 상태를 업데이트 여러 가지 방법이 있는데, 이러한 다양한 방법은 각각의 상황에 맞게 선택되어야 한다. 각 방법의 장단점과 코드 예시를 함께 알아보면서 효율적인 상태 관리를 구현하는 방법을 이해하도록 해보자.&lt;/p&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;1. 콜백 함수를 활용한 상태 업데이트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React의 기본 원칙 중 하나는 단방향 데이터 흐름이다. 부모 컴포넌트는 자식 컴포넌트에게 콜백 함수를 전달하고, 자식 컴포넌트에서 해당 콜백을 호출하여 부모 컴포넌트의 상태를 간접적으로 업데이트할 수 있다. 이는 단방향 데이터 프름을 유지하면서 부모 컴포넌트와 자식 컴포넌트 간의 상태 업데이트를 가능하게 한다. 주로 간단한 구조에서 사용된다.&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;간단하고 직관적인 패턴&lt;/li&gt;
&lt;li&gt;React의 단방향 데이터 흐름을 유지하면서 부모 컴포넌트의 상태를 업데이트할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식 컴포넌트가 부모 컴포넌트에 의존하므로 결합도가 높아진다.&lt;/li&gt;
&lt;li&gt;복잡한 상태 로직이나 여러 컴포넌트 간의 상태 공유에는 제한적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 코드&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 부모 컴포넌트
import { useState } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () =&amp;gt; {
  const [count, setCount] = useState(0);

  const updateCount = (newCount) =&amp;gt; {
    setCount(newCount);
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count: {count}&amp;lt;/p&amp;gt;
      &amp;lt;ChildComponent onUpdateCount={updateCount} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

// 자식 컴포넌트
import React, { useState } from 'react';

const ChildComponent = ({ onUpdateCount }) =&amp;gt; {
  const [newCount, setNewCount] = useState(0);

  const handleClick = () =&amp;gt; {
    onUpdateCount(newCount);
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input
        type=&quot;number&quot;
        value={newCount}
        onChange={(e) =&amp;gt; setNewCount(Number(e.target.value))}
      /&amp;gt;
      &amp;lt;button onClick={handleClick}&amp;gt;
        Update Parent Count
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default ChildComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Context API를 활용한 상태 관리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useContext를 사용하여 부모 컴포넌트의 상태를 전역적으로 공유하는 방법이다. Context를 통해 전역 상태를 제공하고, 자식 컴포넌트에서 해당 상태를 업데이트할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부모 컴포넌트에서 createContext를 사용하여 상태를 생성하고, Provider로 해당 상태를 자식 컴포넌트에 전달한다. 자식 컴포넌트는 useContext를 사용하여 해당 상태를 쉽게 사용하고 업데이트할 수 있다.&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;여러 계층의 컴포넌트 간에 편리하게 상태 전달&lt;/li&gt;
&lt;li&gt;전역적인 상태 관리가 필요한 경우 효과적&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 자식 컴포넌트가 부모 컴포넌트의 상태를 필요로 할 때에만 유용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 코드&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 상태 관리용 Context 생성
import { createContext, useContext, useState } from 'react';

const CountContext = createContext();

export const CountProvider = ({ children }) =&amp;gt; {
  const [count, setCount] = useState(0);

  const updateCount = (newCount) =&amp;gt; {
    setCount(newCount);
  };

  return (
    &amp;lt;CountContext.Provider value={{ count, updateCount }}&amp;gt;
      {children}
    &amp;lt;/CountContext.Provider&amp;gt;
  );
};

// 부모 컴포넌트
import { CountProvider } from './CountContext';

const App = () =&amp;gt; {
  return (
    &amp;lt;CountProvider&amp;gt;
      {/* App 내의 자식 컴포넌트들 */}
    &amp;lt;/CountProvider&amp;gt;
  );
};

// 자식 컴포넌트
import React, { useContext, useState } from 'react';
import { CountContext } from './CountContext';

const ChildComponent = () =&amp;gt; {
  const { count, updateCount } = useContext(CountContext);

  const handleClick = () =&amp;gt; {
    updateCount(count + 1);
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count from Context: {count}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={handleClick}&amp;gt;
        Update Count from Context
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default ChildComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. useReducer를 활용한 상태 업데이트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useReducer 훅을 사용하여 복잡한 상태 로직을 다루는 방법이다.&amp;nbsp;useReducer를 사용하면 복잡한 상태 로직을 다루기에 용이하며, 여러 액션을 통해 상태를 업데이트할 수 있다. 부모 컴포넌트에서 useReducer를 사용하여 상태와 액션을 관리한다. 자식 컴포넌트에 diaspatch 함수를 전달하면 자식 컴포넌트에서 dispatch를 통해 부모 컴포넌트의 상태를 간접적으로 업데이트할 수 있다.&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;복잡한 상태 로직을 다루기에 용이&lt;/li&gt;
&lt;li&gt;여러 액션을 통한 상태 업데이트가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작은 규모의 애플리케이션에서는 useReducer 사용이 오버헤드일 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 코드&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 부모 컴포넌트
import { useReducer } from 'react';
import ChildComponent from './ChildComponent';

const initialState = { count: 0 };

const reducer = (state, action) =&amp;gt; {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    default:
      return state;
  }
};

const ParentComponent = () =&amp;gt; {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count: {state.count}&amp;lt;/p&amp;gt;
      &amp;lt;ChildComponent dispatch={dispatch} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

// 자식 컴포넌트
import React from 'react';

const ChildComponent = ({ dispatch }) =&amp;gt; {
  return (
    &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'INCREMENT' })}&amp;gt;
      Increment
    &amp;lt;/button&amp;gt;
  );
};

export default ChildComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Redux를 이용한 상태 관리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 전역 상태 관리 라이브러리로, 상태를 중앙에서 효율적으로 관리한다. 부모 컴포넌트에서 Redux 스토어를 생성하고, 자식 컴포넌트에서 Redux 액션을 디스패치하여 부모 컴포넌트의 상태를 업데이트할 수 있다.&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;부모 컴포넌트의 상태를 직접 업데이트하는 대신, Redux를 통해 자식 컴포넌트가 간접적으로 부모 컴포넌트와 통신할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작은 규모의 애플리케이션에서는 Redux 사용이 오버헤드일 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 코드&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) Redux 설정&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// actions.js
export const increment = () =&amp;gt; ({
  type: 'INCREMENT',
});

// reducer.js
const initialState = {
  count: 0,
};

const reducer = (state = initialState, action) =&amp;gt; {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    default:
      return state;
  }
};

export default reducer;

// store.js
import { createStore } from 'redux';
import reducer from './reducer';

const store = createStore(reducer);

export default store;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 부모 컴포넌트에서 Redux store 사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부모 컴포넌트에서 Redux store를 생성하고 상태를 업데이트할 액션을 디스패치한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// ParentComponent.js
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { increment } from './actions';

const ParentComponent = () =&amp;gt; {
  const count = useSelector((state) =&amp;gt; state.count);
  const dispatch = useDispatch();

  const handleIncrement = () =&amp;gt; {
    dispatch(increment());
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count: {count}&amp;lt;/p&amp;gt;
      &amp;lt;ChildComponent onIncrement={handleIncrement} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) 자식 컴포넌트에서 action dispatch&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 컴포넌트에서 부모 컴포넌트의 상태를 업데이트하기 위해 action을 dispatch 한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// ChildComponent.js
import React from 'react';

const ChildComponent = ({ onIncrement }) =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={onIncrement}&amp;gt;Increment in Parent&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default ChildComponent;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>React</category>
      <category>context</category>
      <category>Redux</category>
      <category>state</category>
      <category>useReducer</category>
      <category>리액트</category>
      <category>부모 컴포넌트</category>
      <category>상태관리</category>
      <category>자식 컴포넌트</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/211</guid>
      <comments>https://fromnowwon.tistory.com/entry/react-parent-component-state-update#entry211comment</comments>
      <pubDate>Wed, 31 Jan 2024 10:43:51 +0900</pubDate>
    </item>
    <item>
      <title>[클라우드 컴퓨팅] 클라우드 컴퓨팅 특징과 구조</title>
      <link>https://fromnowwon.tistory.com/entry/cloud-computing-structure</link>
      <description>&lt;h2 id=&quot;클라우드-컴퓨팅-특징&quot; data-ke-size=&quot;size26&quot;&gt;1. 클라우드 컴퓨팅 특징&lt;/h2&gt;
&lt;h3 id=&quot;주문형-셀프-서비스-on-demand-self-service&quot; data-ke-size=&quot;size23&quot;&gt;주문형 셀프서비스 (on-demand self service)&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 id=&quot;광대역-네트워크-접근-broad-network-access&quot; data-ke-size=&quot;size23&quot;&gt;광대역 네트워크 접근 (broad network access)&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 id=&quot;자원의-공동관리-resource-pooling-리소스의-공유&quot; data-ke-size=&quot;size23&quot;&gt;자원의 공동관리 (resource pooling, 리소스의 공유)&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 id=&quot;빠른-탄력성-rapid-elasticity-신속한-확장성&quot; data-ke-size=&quot;size23&quot;&gt;빠른 탄력성 (rapid elasticity, 신속한 확장성)&lt;/h3&gt;
&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;h3 id=&quot;측정-가능한-서비스-measured-service&quot; data-ke-size=&quot;size23&quot;&gt;측정 가능한 서비스 (measured service)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이용한 만큼 요금이 부과되는 종량제 서비스임 &amp;rarr; 사용한 만큼 비용을 지불, 생성 기준 X&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;클라우드-컴퓨팅-구조&quot; data-ke-size=&quot;size26&quot;&gt;2. 클라우드 컴퓨팅 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 컴퓨팅 구조는 5 계층으로 구분된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cloud-computing-5-layer.jpg&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;529&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqNRF6/btst5uFnDhJ/uraH9DVuyTNK2eSOiyvVD1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqNRF6/btst5uFnDhJ/uraH9DVuyTNK2eSOiyvVD1/img.jpg&quot; data-alt=&quot;클라우드 컴퓨팅 5계층&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqNRF6/btst5uFnDhJ/uraH9DVuyTNK2eSOiyvVD1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqNRF6%2Fbtst5uFnDhJ%2FuraH9DVuyTNK2eSOiyvVD1%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;600&quot; height=&quot;529&quot; data-filename=&quot;cloud-computing-5-layer.jpg&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;529&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;클라우드 컴퓨팅 5계층&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라우드 제공자(Vendor) 영역: 물리적 시스템 계층, 가상화 계층, 프로비저닝 계층, 서비스 계층&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;h3 id=&quot;계층-물리적-시스템-계층&quot; data-ke-size=&quot;size23&quot;&gt;1 계층 (물리적 시스템 계층)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라우드가 인프라를 구성하는 물리적인 HW 영역&lt;/li&gt;
&lt;li&gt;서버, 스토리지, 네트워크&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;계층-가상화-계층&quot; data-ke-size=&quot;size23&quot;&gt;2 계층 (가상화 계층)&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;가상머신, 가상 스토리지 및 가상 네트워크&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하이퍼바이저, 스토리지 가상화 솔루션 포함
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;가상화: 물리적 구성은 은폐하고, 가상환경을 여러 개 만들어 개별 가상 머신이 자원을 갖추고 있게 만드는 기술&lt;/li&gt;
&lt;li&gt;하이퍼바이저: 물리서버 위에 존재하는 가상화 계층에 포함됨&lt;/li&gt;
&lt;li&gt;OS 구동을 위한 HW 환경을 가상으로 제공함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;계층-프로비저닝-계층&quot; data-ke-size=&quot;size23&quot;&gt;3 계층 (프로비저닝 계층)&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 id=&quot;계층-서비스-관리체계-계층&quot; 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;/li&gt;
&lt;li&gt;다른 계층과 다르게 고객(사용자)이 신경 써야 하는 부분이다&lt;/li&gt;
&lt;li&gt;수동에서 자동화하고 있는 추세이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;계층-서비스-관리체계-계층-1&quot; 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;IaaS, PaaS, SaaS와 같은 서비스를 제공&lt;/li&gt;
&lt;li&gt;관리&amp;amp;책임(R&amp;amp;R)의 범위를 온전하게 이해하고 있어야 미흡이나 부실 없이 효율적으로 관리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>CUK 강의 정리/[이론] 클라우드 컴퓨팅</category>
      <category>5계층</category>
      <category>Cloud Computing</category>
      <category>클라우드 컴퓨팅</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/210</guid>
      <comments>https://fromnowwon.tistory.com/entry/cloud-computing-structure#entry210comment</comments>
      <pubDate>Fri, 15 Sep 2023 14:24:40 +0900</pubDate>
    </item>
    <item>
      <title>[클라우드 컴퓨팅] 클라우드 컴퓨팅이란</title>
      <link>https://fromnowwon.tistory.com/entry/what-is-cloud-computing</link>
      <description>&lt;h2 id=&quot;클라우드-컴퓨팅&quot; data-ke-size=&quot;size26&quot;&gt;1. 클라우드 컴퓨팅&lt;/h2&gt;
&lt;h3 id=&quot;클라우드-컴퓨팅의-개념-서비스의-개념---제공의-대가를-받는&quot; data-ke-size=&quot;size23&quot;&gt;1-1. 클라우드 컴퓨팅의 개념 (서비스의 개념 - 제공의 대가를 받는)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라우드 컴퓨팅&lt;/b&gt;은 서비스의 개념으로, 대가를 받는 형태로 제공된다. 이는 정보통신자원(resource)을 이용자의 요구나 수요 변화에 따라 정보통신망을 통해 유동적으로 이용할 수 있도록 하는 정보처리체계를 의미한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;집적&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;Multi-tenant (다중 고객 공유, 공동 점유) 환경&lt;/b&gt;을 지원한다. (각각 하나하나의 개별적 공간을 tenant라고 한다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;책임-모델&quot; data-ke-size=&quot;size23&quot;&gt;1-2. 책임 모델&lt;/h3&gt;
&lt;h4 id=&quot;클라우드의-책임&quot; data-ke-size=&quot;size20&quot;&gt;클라우드의 책임&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라우드의 책임&lt;/b&gt;은 관리자가 책임지며, 클라우드 관리와 보안을 관리자(Vendor)가 담당한다.&lt;/p&gt;
&lt;h4 id=&quot;클라우드에서의-책임&quot; data-ke-size=&quot;size20&quot;&gt;클라우드에서의 책임&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고객의 책임&lt;/b&gt;은 클라우드 컴퓨팅 공간을 할당 받은 고객이 담당한다. 이는 클라우드의 책임과 고객의 책임이 결합되어 공동 책임 모델을 형성한다. 책임은 클라우드의 부실 또는 미흡함 여부에 따라 판단된다.&lt;/p&gt;
&lt;h4 id=&quot;공동-책임-모델&quot; data-ke-size=&quot;size20&quot;&gt;공동 책임 모델&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객의 책임 + 관리자(Vendor)의 책임 &amp;rArr; 책임도 같이 진다 &amp;rArr; &lt;b&gt;공동 책임 모델&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 본연의 부실이나 미흡인지, 할당받은 공간의 부실이나 미흡인지를 따져서 누구의 책임인지 판단한다.&lt;/p&gt;
&lt;h3 id=&quot;클라우드-서비스와-이용자&quot; data-ke-size=&quot;size23&quot;&gt;1-3. 클라우드 서비스와 이용자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라우드 컴퓨팅&lt;/b&gt;은 유무형의 자원을 제공하고 대가를 받는 하나의 비즈니스 모델이다.&lt;/p&gt;
&lt;h4 id=&quot;이용자&quot; data-ke-size=&quot;size20&quot;&gt;이용자&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이용자&lt;/b&gt;는 필요한 IT 자원(소프트웨어, 스토리지, 서버, 네트워크)을 필요한 만큼 빌려서 사용하며, 사용한 만큼만 비용을 지불하며 계약에 구속되지 않는다. (Lock-in 되지 않는다)&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&quot;Lock-in&quot;은 한 번 선택한 기술 또는 서비스에 종속되어 다른 옵션으로 전환하기 어렵다는 의미이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;클라우드-컴퓨팅-1&quot; data-ke-size=&quot;size20&quot;&gt;클라우드 컴퓨팅&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라우드 컴퓨팅은 서비스의 부하(지연, 중단 발생)에 따라서 실시간 확장성을 제공한다. (임계구간을 넘어서면 자동화된 대응을 한다)&lt;/li&gt;
&lt;li&gt;비용은 사용한 만큼 지불하며, 사용하지 않을 때는 자원을 종료하여 비용을 절감할 수 있다. (생성한 만큼 지불 X)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;클라우드-컴퓨팅의-역사&quot; data-ke-size=&quot;size23&quot;&gt;1-4. 클라우드 컴퓨팅의 역사&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 컴퓨팅의 개념은 오랜 역사를 가지고 있으며, 미국 전산학자 존 메카시(1965)가 &quot;앞으로의 컴퓨팅 환경은 공공 서비스를 사용하는 것과 같다&quot;라는 개념으로 시작되었다. 이후, 구글의 전 최고 경영자 에릭 슈미트(2016)가 &amp;lsquo;클라우드 컴퓨팅&amp;rsquo; 용어를 대중에게 널리 알림으로써 클라우드 컴퓨팅이 대중에게 알려지게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 컴퓨팅의 역사는 중요한 발전 단계를 거쳐왔다. 그 중 하나가 &lt;b&gt;4차 산업 혁명&lt;/b&gt;과 관련된 시기이다. 이 시기에서는 클라우드 컴퓨팅이 중요한 역할을 하게 되었다. 4차 산업 혁명의 개념은 기술과 정보통신 기술의 발전을 토대로 새로운 산업 패러다임이 형성되는 것을 의미한다. 이와 함께 &lt;b&gt;ICDM(Internet of Things, Cloud, Data, and Mobility)&lt;/b&gt;가 &lt;b&gt;PoC(Proof of Concept)&lt;/b&gt; 단계로 발전하였다.&lt;/p&gt;
&lt;h3 id=&quot;클라우드-컴퓨팅의-특징&quot; data-ke-size=&quot;size23&quot;&gt;1-5. 클라우드 컴퓨팅의 특징&lt;/h3&gt;
&lt;h4 id=&quot;인터넷-기반&quot; data-ke-size=&quot;size20&quot;&gt;인터넷 기반&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 컴퓨팅은 인터넷을 기반으로 자원을 제공하며, 이를 통해 원격지에서도 손쉽게 접근할 수 있다.&lt;/p&gt;
&lt;h4 id=&quot;구성-가능한-컴퓨팅-자원-tamplate화&quot; data-ke-size=&quot;size20&quot;&gt;구성 가능한 컴퓨팅 자원 (Tamplate화)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드는 컴퓨팅 자원을 템플릿화(Template화)하여 제공한다. 이는 미리 조립되어 있어 마치 밀키트처럼 고객 목적에 맞는 구성을 쉽게 선택하고 제공할 수 있다는 의미이다. (프로비저닝)&lt;/p&gt;
&lt;h4 id=&quot;주문형-접근-on-demand&quot; data-ke-size=&quot;size20&quot;&gt;주문형 접근 (on-demand)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 컴퓨팅은 주문 요구에 맞춰서 커스터마이징 가능하며, 필요한 리소스를 필요한 시점에 즉시 사용할 수 있는 특징을 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 클라우드 컴퓨팅은 여러 다른 형태로 제공될 수 있다.&lt;/p&gt;
&lt;h4 id=&quot;프라이빗-클라우드--컨소시움-클라우드--폐쇄형-클라우드&quot; data-ke-size=&quot;size20&quot;&gt;프라이빗 클라우드 (= 컨소시움 클라우드 = 폐쇄형 클라우드)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터넷을 기반으로 하지 않고, 내부 시스템에서 클라우드 형태의 자원을 운영하는 모델을 가리킨다. 이는 조직 내에서 클라우드를 직접 구축하는 MAKE(직접 만듦) 개념을 채택하며, 주로 내부 직원들 간의 사용을 위해 구축된다. (내부에서는 직원들끼리 인터넷 기반하여 사용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 다양한 유형의 클라우드는 기업과 조직의 요구사항, 보안 요건, 비용 효율성을 고려하여 선택된다. 클라우드 컴퓨팅은 이러한 다양한 모델을 통해 기업과 사용자에게 유연하고 효율적인 컴퓨팅 환경을 제공한다.&lt;/p&gt;
&lt;h3 id=&quot;클라우드-컴퓨팅-구성&quot; data-ke-size=&quot;size23&quot;&gt;1-6. 클라우드 컴퓨팅 구성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 컴퓨팅은 Storage, Server, Software 등 각각을 하나의 자원으로 관리하며, 이를 빌려서 사용한다. 이러한 자원은 페널티 없이 사용 가능하며, 다양한 endpoint(브라우저, 모바일, 사물인터넷 등)로 접근할 수 있는 호환성을 가지고 있다.&lt;/p&gt;
&lt;h4 id=&quot;패널티-없이-사용-가능&quot; data-ke-size=&quot;size20&quot;&gt;페널티 없이 사용 가능&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;페널티 없이 사용 가능하다&quot;는 클라우드 컴퓨팅의 장점인 자원 사용의 유연성과 비용 효율성을 강조하는 표현이다. 이것은 클라우드 컴퓨팅에서 사용자가 필요한 자원을 동적으로 할당하고 사용할 수 있으며, 이를 통해 자원의 사용에 따른 추가 비용이나 제약이 없다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구체적으로 다음과 같은 의미를 포함한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&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;: 클라우드 컴퓨팅은 다양한 종류의 endpoint(브라우저, 모바일, 사물인터넷 디바이스 등)를 지원하며, 어디서든 접근이 가능하다. 따라서 사용자는 자신이 편한 환경에서 클라우드 자원에 접근할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 특성들은 사용자에게 자원을 더 효과적으로 활용하고 비즈니스 요구사항에 더 민첩하게 대응할 수 있도록 도와준다.&lt;/p&gt;
&lt;h4 id=&quot;레거시lagacy-시스템-vs.-클라우드&quot; data-ke-size=&quot;size20&quot;&gt;레거시(Lagacy) 시스템 vs. 클라우드&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 88px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot;&gt;특징&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot;&gt;Legacy 시스템&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot;&gt;클라우드 컴퓨팅&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;b&gt;자원 단위&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;물리적 장비 단위 (고정비용)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;VM (가상 머신) 최소 단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;b&gt;과금 방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;임대 또는 하드웨어에 따른 과금&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;사용량 기반 (효율적인 비용 절감 필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;b&gt;인프라 구축&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;별도의 하드웨어 구축 및 유지&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;셀프 서비스 (on-demand, 필요할 때 자원 할당, like 키오스크)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;b&gt;업그레이드 및 관리 비용&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;업그레이드 및 관리 비용 발생&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;낮은 유지 비용 (사용료에 포함, 항상 최신 버전 사용 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;추상화abstraction와-가상화virtualization&quot; data-ke-size=&quot;size23&quot;&gt;1-7. 추상화(Abstraction)와 가상화(Virtualization)&lt;/h3&gt;
&lt;h4 id=&quot;추상화&quot; data-ke-size=&quot;size20&quot;&gt;추상화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추상화&lt;/b&gt;는 사용자가 몰라도 되는 복잡하고 어려운 부분을 은닉하여 중요한 특징만을 노출하는 것을 의미한다. 클라우드는 사용자에게 느슨한 추상성을 제공한다.&lt;/p&gt;
&lt;h4 id=&quot;가상화&quot; data-ke-size=&quot;size20&quot;&gt;가상화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상화는 하나의 물리적 컴퓨터 하나에서 여러 개의 가상 컴퓨터(가상 머신)를 만들어내는 기술이다. 가상화를 사용하면 하나의 물리적 서버에서 여러 개의 독립적인 운영 체제(OS)와 애플리케이션을 실행할 수 있다.&lt;/p&gt;
&lt;h4 id=&quot;가상화와-호환성&quot; data-ke-size=&quot;size20&quot;&gt;가상화와 호환성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호환성은 다른 시스템, 소프트웨어, 또는 하드웨어와의 상호 작용 또는 연결 가능성을 나타낸다. 호환성이 있는 시스템 또는 소프트웨어는 서로 작동하거나 통신할 수 있으며, 호환성이 부족한 경우에는 문제가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상화 기술은 물리적 머신의 자원을 여러 개의 가상 머신으로 나누어 사용할 수 있게 한다. 호환성은 이러한 가상 머신이 서로 다른 운영 체제(OS)나 환경에서도 원활하게 동작하고 통신할 수 있어야 함을 의미한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;가상화에는 호환성이 필요하다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;가상화는 다양한 운영 체제 및 환경 간에 호환성을 유지해야 한다. 이것은 서로 다른 소프트웨어 및 하드웨어 구성 요소 간의 원활한 상호 작용을 보장하는 중요한 측면이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;물리적 머신과 가상화하는 가상화 솔루션에는 물리적 머신의 본질적인 속성을 그대로 가져간다. (여기에 호환성이 필요한 것이다.)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;가상화 솔루션은 물리적 머신의 핵심 특성을 보존하고, 가상 환경에서도 물리적 머신과 유사한 동작을 유지하도록 설계된다. 이것은 호환성을 유지하고 이식성을 향상하는데 도움이 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Endpoint의 호환성: 클라우드에 접근하기 위한 호환성 (다양한 Endpoint로 접근할 수 있음)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;가상화는 다양한 종류의 디바이스 또는 Endpoint를 통해 클라우드 서비스에 접근할 수 있도록 해준다. 이것은 다양한 디바이스 및 환경에서 일관된 경험을 제공하는 데 중요하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Resource의 호환성: 다양한 가상머신(OS)을 이용할 수 있는 호환성 (물리적 머신의 호환성 극복)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;과거 가상화 솔루션에서는 가상 머신 안에서 window용 머신 만들면 window용 머신을 통해서만 window OS가 사용 가능했다.&lt;/li&gt;
&lt;li&gt;가상화 솔루션의 한계를 벗어나서 물리적 머신에 상관없이 다양한 가상 머신을 사용할 수 있게 되었다.&lt;/li&gt;
&lt;li&gt;가상 머신도 100GB라면 200GB의 성능과 용량을 만들어낼 수는 없다 &amp;rarr; 물리적 머신의 한계 상속됨&lt;/li&gt;
&lt;li&gt;가상화는 다양한 운영 체제(OS)를 가진 가상 머신을 호환성 있게 운영할 수 있도록 한다. 이것은 물리적 머신의 제약을 극복하고, 서로 다른 운영 체제를 동일한 환경에서 실행할 수 있도록 해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;클라우드-컴퓨팅의-성장&quot; data-ke-size=&quot;size26&quot;&gt;2. 클라우드 컴퓨팅의 성장&lt;/h2&gt;
&lt;h3 id=&quot;년부터-확산된-클라우드-컴퓨팅-변화&quot; data-ke-size=&quot;size26&quot;&gt;2006년부터 확산된 클라우드 컴퓨팅 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어 중심 &amp;rarr; 설치형 소프트웨어 &amp;rarr; 하드웨어/소프트웨어를 서비스 형태로 사용하는 클라우드 시대&lt;/p&gt;
&lt;h3 id=&quot;ict-패러다임의-변화&quot; data-ke-size=&quot;size23&quot;&gt;ICT 패러다임의 변화&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ICT(Information and Communication Technology, 정보통신기술) 패러다임이 환경과 비즈니스 측면에서 변화 중이다.&lt;/li&gt;
&lt;li&gt;IoT, 빅데이터, 모바일 등 (ICBM, IoT Cloud Bigdata Mobile)이 급격히 성장하며 데이터 양이 폭증하고 있다.&lt;/li&gt;
&lt;li&gt;그중 클라우드는 데이터 트래픽의 약 76%를 저장하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;클라우드-시장-규모도-전세계-연평균-16.9-국내-17.7로-급성장하고-있음&quot; data-ke-size=&quot;size23&quot;&gt;클라우드 시장 규모도 전 세계 연평균 16.9%, 국내 17.7%로 급성장하고 있음&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비용절감, 업무확산을 위해 정보 시스템을 자체 구축하는 기존의 방식 &amp;rarr; 정보자원을 빌려 쓰는 클라우드 컴퓨팅 방식 (스마트워크에 맞춰 패러다임이 변화하고 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rArr; 패러다임이 변화하고 있음을 반증함&lt;/p&gt;
&lt;h3 id=&quot;클라우드-서비스-시장-현황&quot; 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;클라우드 시장의 성장세는 반도체, SW 등 타 ICT 산업의 성장률을 상회&lt;/li&gt;
&lt;li&gt;AWS가 49.6%를 점유하며 클라우드 시장 과점 중&lt;/li&gt;
&lt;li&gt;IaaS, PaaS는 인프라에 대한 구축 관련, 인프라에 대한 개념과 지식이 있어야 한다.&lt;/li&gt;
&lt;li&gt;그러나 SaaS는 호기심만으로도 접근이 가능하다 (접근성 좋음 &amp;rarr; SaaS가 크게 성장하고 있다.)&lt;/li&gt;
&lt;li&gt;클라우드 관련 예산 계획은 금융, 물류, 제조 등 산업의 대폭 상향이 예상되어 동 산업들의 향후 클라우드 활용 증가 기대&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;클라우드-컴퓨팅의-구성-요소&quot; data-ke-size=&quot;size26&quot;&gt;3. 클라우드 컴퓨팅의 구성 요소&lt;/h2&gt;
&lt;h3 id=&quot;클라우드-컴퓨팅의-구성요소&quot; data-ke-size=&quot;size23&quot;&gt;클라우드 컴퓨팅의 구성요소&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 클라우드 컴퓨팅의 주요 구성요소&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보안장비&lt;/li&gt;
&lt;li&gt;서브넷 분리 또는 부하분산을 위한 네트워크 장비&lt;/li&gt;
&lt;li&gt;클라우드 자원을 관리하는 클라우드 인프라 관리 서버 (분산)&lt;/li&gt;
&lt;li&gt;가상 머신이 구동되는 가상 서버 (&amp;larr; 가상화)&lt;/li&gt;
&lt;li&gt;스토리지: 클라우드 사용자가 가상서버를 통해 생성한 데이터를 저장하는 공간&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;클라우드-컴퓨팅-구성원&quot; 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;기업의 일반 사용자&lt;/li&gt;
&lt;li&gt;클라우드 서비스를 이용&lt;/li&gt;
&lt;li&gt;기업 내부 관리자&lt;/li&gt;
&lt;li&gt;클라우드 서비스 제공자로부터 할당받은 VM을 내부적으로 분배&lt;/li&gt;
&lt;li&gt;클라우드 서비스 제공자 (관리자, CSP)&lt;/li&gt;
&lt;li&gt;클라우드 시스템의 서버, 스토리지 등의 자원과 전체 클라우드 영역의 자원 사용률을 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;클라우드-컴퓨팅-구성요소-별-역할&quot; data-ke-size=&quot;size23&quot;&gt;클라우드 컴퓨팅 구성요소 별 역할&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;보안장비&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방화벽, IDS, IPS, DDoS 장비, VPN 등이 있으며, 외부 공격 대응 및 안전한 통신을 위한 장비&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;네트워크 장비&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우터, 스위치 등이 있으며, 트래픽 부하 분산 및 서브넷(영역) 분리를 위한 장비&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;접근제어시스템&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 서비스 관리 영역에 대한 접근 감시, 허용, 차단&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클라우드 인프라 관리서버&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IT 자원과 전체 클라우드 서비스 사용자의 자원 사용률 등을 관리&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인증 서버&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 환경에 접근이 허용된 사용자를 등록, 관리하며, VM에 접근하는 사용자 인증&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;관리 서버&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 서비스 제공자로부터 할당받은 VM을 기업 내부적으로 할당&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;가상 서버&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하이퍼바이저 기술을 이용해 다수의 가상머신을 구동&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스토리지&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 사용자가 가상서버를 활용하여 생성한 데이터를 저장하는 공간&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DB&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 정보, 금융정보 등 민감 정보 저장함. 따라서, DB는 주로 외부망과 분리되어 있는 Private Zone에 구축&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CUK 강의 정리/[이론] 클라우드 컴퓨팅</category>
      <category>Cloud Computing</category>
      <category>클라우드 컴퓨팅</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/209</guid>
      <comments>https://fromnowwon.tistory.com/entry/what-is-cloud-computing#entry209comment</comments>
      <pubDate>Fri, 15 Sep 2023 13:41:30 +0900</pubDate>
    </item>
    <item>
      <title>[react-router-dom v6] 전역 컴포넌트 사용과 라우팅 구조화</title>
      <link>https://fromnowwon.tistory.com/entry/react-router-dom-v6-global-component</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;전역적으로 보여야 하는 컴포넌트는 어디에 &lt;code&gt;import&lt;/code&gt; 해야 할까? react-router-dom v6 버전에서는 이전 버전과는 다른 라우팅 방식이 도입되었다. 이에 따라 Navbar 컴포넌트를 어디에서 &lt;code&gt;import&lt;/code&gt; 해야 하는지에 대한 접근도 바뀌었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;v6에서는 아래 코드와 같이 App.js에 전역 컴포넌트를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;import&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하면 에러가 날 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1692073359388&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function App() {
  return (
    &amp;lt;&amp;gt;
        {/* 전역 컴포넌트 */}
        &amp;lt;Navbar /&amp;gt;
        {/* 라우팅 */}
        &amp;lt;BrowserRouter&amp;gt;
            &amp;lt;Routes&amp;gt;
                &amp;lt;Route path=&quot;/&quot; element={&amp;lt;HomePage /&amp;gt;} /&amp;gt;
                &amp;lt;Route path=&quot;/super-heroes&quot; element={&amp;lt;SuperHeroesPage /&amp;gt;} /&amp;gt;
            &amp;lt;/Routes&amp;gt;
        &amp;lt;/BrowserRouter&amp;gt;
    &amp;lt;/&amp;gt;
  )
}

export default App&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;react-router-dom-v6-error.png&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;966&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCuF3b/btsq5cBk5Is/WvdN8kfZVG8K6KZkmh5KaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCuF3b/btsq5cBk5Is/WvdN8kfZVG8K6KZkmh5KaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCuF3b/btsq5cBk5Is/WvdN8kfZVG8K6KZkmh5KaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCuF3b%2Fbtsq5cBk5Is%2FWvdN8kfZVG8K6KZkmh5KaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1446&quot; height=&quot;966&quot; data-filename=&quot;react-router-dom-v6-error.png&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;966&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  Cannot destructure property 'basename' of 'react__WEBPACK_IMPORTED_MODULE_0__.useContext(...)' as it is null&amp;hellip;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt; &amp;nbsp;The above error occurred in the component&amp;hellip;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;라우팅-구조화&quot; data-ke-size=&quot;size26&quot;&gt;라우팅 구조화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-router-dom v6에서는 라우트와 레이아웃을 분리하는 패턴을 권장한다. 따라서, Navbar와 같은 전역적인 컴포넌트를 App.js와 함께 사용하면 라우팅 관련 문제가 발생할 수 있다. 대신에 다음과 같이 컴포넌트 구조를 구조화하면 해당 문제를 해결할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Layout 컴포넌트 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 레이아웃 컴포넌트를 생성한다. 이 레이아웃 컴포넌트는 &lt;code&gt;Navbar&lt;/code&gt;와 같은 전역 컴포넌트를 포함할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692073508439&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Layout.js
import Navbar from './Nav';

const Layout = () =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
        {/* 전역 컴포넌트 */}
        &amp;lt;Navbar /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Layout;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Outlet으로 하위 컴포넌트 전달하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Layout&lt;/code&gt; 컴포넌트로 묶인 하위 컴포넌트를 라우팅에 따라 출력하려면 &lt;code&gt;Outlet&lt;/code&gt; 컴포넌트를 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1692273728833&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Layout.js
import Navbar from './Nav';
import { Outlet } from 'react-router';

const Layout = () =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
        {/* 전역 컴포넌트 */}
        &amp;lt;Navbar /&amp;gt;
        {/* 라우팅에 따라 전달되는 하위 컴포넌트 */}
        &amp;lt;Outlet /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Layout;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 라우트 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Layout&lt;/code&gt; 컴포넌트로 하위 컴포넌트를 묶어주면 그 하위 컴포넌트가 위에서 설정한 &lt;code&gt;Outlet&lt;/code&gt;컴포넌트 위치에서 출력된다. path에 따라서 각 하위 컴포넌트가 출력된다. 사실 아래와 같은 방법은 많이 사용하지 않고 두 번째 방법을 많이 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692073607099&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// App.js
import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Layout from './Layout';
import Home from './Home';
import About from './About';

const App = () =&amp;gt; {
  return (
    &amp;lt;BrowserRouter&amp;gt;
        &amp;lt;Routes&amp;gt;
            &amp;lt;Route path=&quot;/&quot; element={&amp;lt;Layout&amp;gt;&amp;lt;HomePage /&amp;gt;&amp;lt;/Layout&amp;gt;} /&amp;gt;
            &amp;lt;Route path=&quot;/super-heroes&quot; element={&amp;lt;Layout&amp;gt;&amp;lt;SuperHeroesPage /&amp;gt;&amp;lt;/Layout&amp;gt;} /&amp;gt;
        &amp;lt;/Routes&amp;gt;
    &amp;lt;/BrowserRouter&amp;gt;
  );
};

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 &lt;code&gt;Layout&lt;/code&gt; 컴포넌트로 감싸는 게 번거롭다면 아래와 같이 중첩 방식으로 라우트를 설정하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1692073626916&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// App.js
const App = () =&amp;gt; {
  return (
    &amp;lt;BrowserRouter&amp;gt;
      &amp;lt;Routes&amp;gt;
        &amp;lt;Route path=&quot;/&quot; element={&amp;lt;Layout /&amp;gt;} &amp;gt; {/* 전역 컴포넌트 */}
          &amp;lt;Route index element={&amp;lt;HomePage /&amp;gt;} /&amp;gt;
          &amp;lt;Route path=&quot;/super-heroes&quot; element={&amp;lt;SuperHeroesPage /&amp;gt;} /&amp;gt;
        &amp;lt;/Route&amp;gt;
      &amp;lt;/Routes&amp;gt;
    &amp;lt;/BrowserRouter&amp;gt;
  );
};

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 &lt;code&gt;Layout&lt;/code&gt; 컴포넌트는 &lt;code&gt;Routes&lt;/code&gt; 컴포넌트 내에서 렌더링 되며, 그 안에 페이지 컴포넌트가 중첩된다. 이 방법을 사용하면 매번 &lt;code&gt;Layout&lt;/code&gt; 컴포넌트를 감싸지 않아도 되므로 코드가 더 간결해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 라우팅이 구조화된 코드는 Navbar와 같은 전역 컴포넌트를 라우트와 분리하여 사용하므로, 라우팅 관련 문제가 발생하지 않게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(참고) Route의 index prop&lt;/h4&gt;
&lt;pre id=&quot;code_1692074781043&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Route index element={&amp;lt;HomePage /&amp;gt;} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 웹사이트의 루트 경로인 &lt;code&gt;/&lt;/code&gt;를 방문하면, &lt;code&gt;Layout&lt;/code&gt; 컴포넌트가 렌더링 되고 동시에 &lt;code&gt;index&lt;/code&gt; prop으로 지정된 &lt;code&gt;HomePage&lt;/code&gt; 컴포넌트가 렌더링 된다. 이렇게 함으로써 기본 페이지를 설정할 수 있게 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;index&lt;/code&gt; prop을 사용하여 기본 페이지를 설정하면, 해당 경로에 대한 URL을 직접 입력하지 않고도 웹사이트의 기본 화면을 보여줄 수 있다.&amp;nbsp;&lt;code&gt;Routes&lt;/code&gt; 컴포넌트에서 &lt;code&gt;Route&lt;/code&gt; 컴포넌트의 &lt;code&gt;index&lt;/code&gt; prop은 해당 경로가 기본 페이지로 사용되는 경우에 적용된다. 즉, 해당 경로에 대한 URL이 매칭되었을 때, &lt;code&gt;index&lt;/code&gt; prop으로 지정된 컴포넌트가 렌더링 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>React</category>
      <category>navbar</category>
      <category>react-router-dom v6</category>
      <category>전역 컴포넌트</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/208</guid>
      <comments>https://fromnowwon.tistory.com/entry/react-router-dom-v6-global-component#entry208comment</comments>
      <pubDate>Tue, 15 Aug 2023 13:47:48 +0900</pubDate>
    </item>
    <item>
      <title>라이브러리와 프레임워크 차이</title>
      <link>https://fromnowwon.tistory.com/entry/library-framework</link>
      <description>&lt;h2 id=&quot;라이브러리&quot; data-ke-size=&quot;size26&quot;&gt;라이브러리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이브러리(Library)는 개발자가 자주 사용하는 기능들을 모아놓은 도구들의 집합이다. 이 도구들을 사용하면 개발자가 웹사이트나 앱을 더 쉽고 빠르게 만들 수 있다. 예를 들어, 'jQuery&amp;rsquo;라는 라이브러리는 HTML 요소를 선택하고 조작하는데 도움을 주는 기능들을 제공한다. 자바스크립트의 DOM(Document Object Model) 조작은 웹사이트에서 HTML 요소들을 선택하고 조작하는 작업을 의미한다. 자바스크립트의 내장 기능으로도 DOM을 다룰 수 있지만, &amp;lsquo;jQuery&amp;rsquo; 라이브러리를 사용하면 더 쉽게 DOM을 조작할 수 있다. jQuery는 간단한 문법을 제공하여 선택, 수정, 이벤트 처리 등을 쉽게 처리할 수 있도록 도와준다. 개발자가 간단한 코드 몇 줄로 요소들을 다룰 수 있게 해주는 것이다.&lt;/p&gt;
&lt;h2 id=&quot;프레임워크&quot; data-ke-size=&quot;size26&quot;&gt;프레임워크&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프레임워크(Framework)는 라이브러리보다 더 큰 개념이다. 프레임워크는 개발자가 웹사이트나 앱의 구조를 만들 때 도움을 주는 기반 구조를 제공한다. 개발자는 프레임워크 안에서 작업을 하며, 프레임워크가 웹사이트의 흐름을 제어하고 필요한 기능들을 제공해 주는 것이다. 예를 들어, 'React&amp;rsquo;나 &amp;lsquo;Angular&amp;rsquo; 같은 프레임워크는 컴포넌트 기반 구조를 제공하여 웹사이트를 빠르게 개발할 수 있게 해 준다. 예를 들어, 웹사이트에 댓글 기능을 추가하려면 댓글 작성, 댓글 목록, 댓글 삭제 등의 기능이 필요하다. 이때 리액트를 사용하면 댓글 작성용 컴포넌트, 댓글 목록용 컴포넌트, 댓글 삭제용 컴포넌트 등을 만들어 두고, 필요한 곳에서 이 컴포넌트들을 가져와서 조합할 수 있다. 이러한 구조를 통해 코드의 재사용성과 유지보수가 용이해진다.&lt;/p&gt;
&lt;h2 id=&quot;정리&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이브러리를 이용하면 더 쉽게 개발할 수 있고, 리액트와 같은 프레임워크를 이용하면 보다 구조화된 개발이 가능해진다. 간단히 말하면, 라이브러리는 개발자가 필요할 때 가져다 쓸 수 있는 &amp;lsquo;도구&amp;rsquo;들의 집합이고, 프레임워크는 개발자가 따라야 할 &amp;lsquo;구조&amp;rsquo;를 제공하여 개발을 도와주는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 라이브러리와 프레임워크는 개발에서 효율성과 생산성을 높여주는 중요한 도구들이다.&lt;/p&gt;</description>
      <category>Programming</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/207</guid>
      <comments>https://fromnowwon.tistory.com/entry/library-framework#entry207comment</comments>
      <pubDate>Sun, 30 Jul 2023 16:04:07 +0900</pubDate>
    </item>
    <item>
      <title>JSP란? 사용 이유, JSTL 라이브러리, HTML과의 차이점</title>
      <link>https://fromnowwon.tistory.com/entry/jsp-jstl</link>
      <description>&lt;h2 id=&quot;jsp란&quot; data-ke-size=&quot;size26&quot;&gt;JSP란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP는 Java Server Pages의 약자로, 서버 측에서 동적 웹 페이지를 생성하기 위해 사용되는 기술이다. JSP는 HTML 문서 안에 Java 코드를 삽입하여 웹 페이지를 동적으로 생성할 수 있게 해 준다.&lt;/p&gt;
&lt;h2 id=&quot;jsp와-html의-차이점&quot; data-ke-size=&quot;size26&quot;&gt;JSP와 HTML의 차이점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML과의 가장 큰 차이점은 JSP에서는 Java 코드를 사용할 수 있다는 것이다. JSP는 서버 측에서 실행되고 동적인 기능을 처리하는 반면, HTML은 클라이언트 측에서 실행되고 정적인 페이지의 구조를 표현한다. JSP는 Java 코드를 사용하여 데이터 처리와 로직을 구현할 수 있으며, 서버에서 동적인 데이터를 생성하여 클라이언트에게 전달한다. HTML은 단순히 페이지의 구조와 내용을 정의하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP는 서버 사이드 스크립트 언어이므로, 서버 측에서 실행되는 로직과 데이터베이스와의 상호작용 등을 처리할 수 있다. HTML은 클라이언트 측에서 실행되므로, 사용자 인터페이스와 상호작용을 위한 기능을 구현하는 데 주로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 차이점으로 인해 JSP와 HTML은 서로 보완적으로 사용되며, 백엔드와 프론트엔드 간의 협업을 통해 동적이고 상호작용이 가능한 웹 애플리케이션을 개발할 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;jsp-동작-원리&quot; data-ke-size=&quot;size26&quot;&gt;JSP 동작 원리&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;클라이언트(웹 브라우저)가 JSP 페이지를 요청한다.&lt;/li&gt;
&lt;li&gt;JSP 컨테이너(서블릿 컨테이너)는 해당 JSP 페이지를 서블릿으로 변환한다. 이 서블릿은 Java 코드로 작성되며, 동적인 데이터 처리와 HTML 생성을 수행한다.&lt;/li&gt;
&lt;li&gt;서블릿은 컴파일된 후에 실행 가능한 형태로 만들어진다.&lt;/li&gt;
&lt;li&gt;서블릿이 생성된 후에는 요청된 JSP 페이지에 대한 응답을 처리하기 위해 실행된다.&lt;/li&gt;
&lt;li&gt;서블릿은 필요한 데이터를 처리하고, Java 코드 내에 포함된 HTML 템플릿과 함께 최종적인 HTML 페이지를 생성한다.&lt;/li&gt;
&lt;li&gt;생성된 HTML은 클라이언트로 전달되어 웹 브라우저에 응답으로 표시된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 JSP 컨테이너는 JSP 파일의 Java 코드 부분을 서블릿으로 변환하고, 서블릿을 실행하여 필요한 데이터 처리와 HTML 생성을 수행한다. 이를 통해 동적인 데이터를 처리하고 HTML을 생성하는 것이 가능해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP는 Java 코드와 HTML을 혼합하여 작성되므로, Java 코드 부분은 &lt;code&gt;&amp;lt;% %&amp;gt;&lt;/code&gt; 태그로 감싸져 있다. JSP 컨테이너는 이 태그 내의 Java 코드를 실행하여 동적인 데이터 처리를 수행하고, 그 결과를 HTML로 변환하여 클라이언트에게 전달한다.&lt;/p&gt;
&lt;h2 id=&quot;자바-프로젝트-디렉토리-구조-예시&quot; data-ke-size=&quot;size26&quot;&gt;자바 프로젝트 디렉터리 구조 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 프로젝트의 일반적인 디렉토리 구조는 다음과 같다. 프로젝트의 규모와 구성에 따라 조금씩 달라질 수 있다.&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;프로젝트명
├── src
│   ├── main
│   │   ├── java
│   │   │   └── 패키지명
│   │   │       └── 소스 파일들.java
│   │   └── resources
│   │       └── 설정 파일들, 리소스 파일들
│   └── test
│       ├── java
│       │   └── 패키지명
│       │       └── 테스트 소스 파일들.java
│       └── resources
│           └── 테스트 설정 파일들, 리소스 파일들
├── WebContent 또는 webapp
│   ├── WEB-INF
│   │   ├── lib
│   │   │   └── 라이브러리 파일들.jar
│   │   ├── classes
│   │   │   └── 컴파일된 클래스 파일들
│   │   └── web.xml
│   └── JSP 파일들, CSS 파일들, JavaScript 파일들, 이미지 파일들 등
└── pom.xml 또는 build.gradle (빌드 도구 설정 파일)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP 파일들은 &lt;code&gt;WebContent&lt;/code&gt; 또는 &lt;code&gt;webapp&lt;/code&gt; 디렉터리에 위치한다. 이 디렉토리는 웹 애플리케이션의 루트 디렉토리로서, 클라이언트(웹 브라우저)에게 제공되는 웹 리소스들을 포함한다. JSP 파일은 해당 디렉토리 내에 위치하며, 프론트엔드 개발자가 주로 작업하는 영역이다. 프론트엔드 개발자는 JSP 파일을 통해 HTML, CSS, JavaScript 등을 작성하여 웹 페이지의 디자인과 동적인 기능을 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 애플리케이션의 구성 파일인 &lt;code&gt;web.xml&lt;/code&gt;은 &lt;code&gt;WEB-INF&lt;/code&gt; 디렉토리에 위치한다. 이 파일은 서블릿 컨테이너에게 웹 애플리케이션의 구성 정보를 제공하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같은 디렉토리 구조는 Java 프로젝트에서 백엔드와 프론트엔드 간의 협업을 용이하게 하고, 코드와 리소스의 관리를 효과적으로 할 수 있도록 한다.&lt;/p&gt;
&lt;h2 id=&quot;jstl-라이브러리&quot; data-ke-size=&quot;size26&quot;&gt;JSTL 라이브러리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSTL(JavaServer Pages Standard Tag Library)은 JSP를 보다 효율적으로 개발하기 위해 제공되는 라이브러리다. JSTL은 JSP에서 반복문, 조건문, 변수 설정 등과 같은 일반적인 작업을 수행하기 위한 태그들의 집합이다. JSP에서 스크립트릿(&lt;code&gt;&amp;lt;% %&amp;gt;&lt;/code&gt;) 태그를 사용하지 않고도 JSTL 태그를 활용하여 작업을 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSTL을 사용하면 JSP 코드의 가독성과 유지보수성이 향상되며, 개발자는 더욱 효율적으로 JSP를 개발할 수 있다. JSTL은 Java 표준으로 정의되어 있어 다양한 JSP 컨테이너에서 지원된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSTL은 여러 가지 기능을 제공하는 태그 라이브러리로 구성되어 있다. 예를 들어, &lt;code&gt;c:forEach&lt;/code&gt; 태그는 컬렉션을 반복하면서 값을 처리할 수 있고, &lt;code&gt;c:if&lt;/code&gt; 태그는 조건문을 수행할 수 있다. 이 외에도 &lt;code&gt;c:set&lt;/code&gt;, &lt;code&gt;c:choose&lt;/code&gt;, &lt;code&gt;c:when&lt;/code&gt;, &lt;code&gt;c:otherwise&lt;/code&gt; 등 다양한 태그들이 있어 JSP에서 보다 간편하고 가독성 높은 코드를 작성할 수 있게 도와준다.&lt;/p&gt;
&lt;h3 id=&quot;jsp만-사용한-코드&quot; data-ke-size=&quot;size23&quot;&gt;JSP만 사용한 코드&lt;/h3&gt;
&lt;pre class=&quot;language-html xml&quot;&gt;&lt;code&gt;&amp;lt;%@ page contentType=&quot;text/html; charset=UTF-8&quot; %&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;순수 JSP 예시&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;회원 목록&amp;lt;/h1&amp;gt;
    
    &amp;lt;% 
        // 회원 목록 데이터
        String[] members = {&quot;John&quot;, &quot;Jane&quot;, &quot;Tom&quot;};
     %&amp;gt;
    
    &amp;lt;ul&amp;gt;
        &amp;lt;% for (String member : members) { %&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;%= member %&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;% } %&amp;gt;
    &amp;lt;/ul&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;jstl을-사용한-코드&quot; data-ke-size=&quot;size23&quot;&gt;JSTL을 사용한 코드&lt;/h3&gt;
&lt;pre class=&quot;language-html xml&quot;&gt;&lt;code&gt;&amp;lt;%@ page contentType=&quot;text/html; charset=UTF-8&quot; %&amp;gt;
&amp;lt;%@ taglib prefix=&quot;c&quot; uri=&quot;&amp;lt;http://java.sun.com/jsp/jstl/core&amp;gt;&quot; %&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;JSTL 예시&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;회원 목록&amp;lt;/h1&amp;gt;
    
    &amp;lt;c:set var=&quot;members&quot; value=&quot;${['John', 'Jane', 'Tom']}&quot; /&amp;gt;
    
    &amp;lt;ul&amp;gt;
        &amp;lt;c:forEach items=&quot;${members}&quot; var=&quot;member&quot;&amp;gt;
            &amp;lt;li&amp;gt;${member}&amp;lt;/li&amp;gt;
        &amp;lt;/c:forEach&amp;gt;
    &amp;lt;/ul&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;렌더링-순서&quot; data-ke-size=&quot;size26&quot;&gt;렌더링 순서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드와 프론트엔드가 Java, JSP, CSS, JavaScript로 협업할 때의 렌더링 순서는 다음과 같다.&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;요청은 백엔드(Java)로 전달된다.&lt;/li&gt;
&lt;li&gt;백엔드에서는 요청에 따라 필요한 데이터 처리와 비즈니스 로직을 수행한다.&lt;/li&gt;
&lt;li&gt;백엔드는 데이터와 함께 JSP 파일을 호출하여 HTML을 생성한다.&lt;/li&gt;
&lt;li&gt;JSP 파일은 Java 코드와 HTML을 포함하고 있으며, 동적인 데이터 처리와 HTML 생성을 담당한다.&lt;/li&gt;
&lt;li&gt;JSP 파일 내에서 생성된 HTML은 클라이언트로 응답된다.&lt;/li&gt;
&lt;li&gt;클라이언트는 받은 HTML을 웹 브라우저에서 해석하고 렌더링 한다.&lt;/li&gt;
&lt;li&gt;렌더링 된 HTML은 화면에 보이며, 이때 CSS 스타일 시트를 적용하여 페이지의 디자인을 결정한다.&lt;/li&gt;
&lt;li&gt;클라이언트(웹 브라우저)는 JavaScript 코드를 해석하고 실행하여 동적인 기능을 구현한다.&lt;/li&gt;
&lt;li&gt;사용자의 상호작용에 따라 JavaScript를 통해 HTML이 동적으로 변경되거나 이벤트가 처리된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드는 데이터 처리와 비즈니스 로직을 담당하고, JSP를 통해 HTML을 생성하여 클라이언트에게 전달한다. 클라이언트는 HTML을 해석하고 렌더링 하며, CSS를 적용하여 디자인을 결정하고 JavaScript를 실행하여 동적인 기능을 구현한다. 이를 통해 완성된 웹 페이지가 사용자에게 제공되는 것이다.&lt;/p&gt;
&lt;h2 id=&quot;jsp-사용-이유&quot; data-ke-size=&quot;size26&quot;&gt;JSP 사용 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP는 Java 기반으로 작성되기 때문에 Java의 강력한 기능과 라이브러리를 활용할 수 있다. 또한 정적인 웹 페이지를 생성하는 HTML로는 동적인 값을 적용하는 데는 제한이 있는데, (ex. 사용자의 입력이나 데이터베이스의 정보를 받아와서 동적으로 웹 페이지를 생성해야 할 때) JSP에서는 Java 코드를 활용하여 동적인 값을 적용할 수 있기 때문에 더욱 유연하고 다양한 기능을 구현할 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;jsp-단점&quot; data-ke-size=&quot;size26&quot;&gt;JSP 단점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디자인과 로직의 분리: JSP는 서버 사이드 스크립트 언어로써, Java 코드와 HTML이 혼재하여 작성된다. 이로 인해 디자인과 로직이 분리되지 않고 섞이는 경향이 있어서 유지보수와 협업을 어렵게 할 수 있다.&lt;/li&gt;
&lt;li&gt;가독성과 유지보수: JSP 파일이 복잡해지면 가독성이 떨어지고 유지보수가 어려워질 수 있다. JSP 파일 안에 많은 양의 Java 코드가 포함되면서 코드의 복잡도가 증가할 수 있다.&lt;/li&gt;
&lt;li&gt;테스트와 디버깅: JSP는 서버 측에서 실행되기 때문에 로컬 환경에서의 테스트와 디버깅이 어려울 수 있다. JSP 파일의 코드와 HTML이 혼재하므로 디버깅에 어려움을 겪을 수 있다.&lt;/li&gt;
&lt;li&gt;성능: JSP는 동적인 웹 페이지를 생성하기 위해 서버 측에서 실행되기 때문에 서버의 부하가 발생할 수 있다. 특히 매 요청마다 JSP 파일이 다시 컴파일되고 실행되어야 하는 단점이 있다.&lt;/li&gt;
&lt;li&gt;확장성과 유연성: JSP는 Java 기반으로 동작하기 때문에 Java의 제약사항과 의존성을 가지고 있다. 이로 인해 다른 언어나 프레임워크와의 통합이 어려울 수 있고, 확장성과 유연성이 제한될 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 단점들은 JSP를 사용할 때 고려해야 할 사항이다. 최근에는 JSP 대신에 프론트엔드 프레임워크와 API 방식을 활용하여 더 유연하고 모던한 웹 애플리케이션을 개발하는 추세이다.&lt;/p&gt;
&lt;h2 id=&quot;최신-동향&quot; data-ke-size=&quot;size26&quot;&gt;최신 동향&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘에는 JSP 외에도 프론트엔드 자체에서 동적으로 작업할 수 있는 언어 및 기술들이 많이 등장하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript를 비롯한 클라이언트 사이드 스크립트 언어들은 웹 브라우저에서 동적인 기능을 구현하는 데 많이 활용된다. JavaScript를 사용하여 웹 페이지의 동적인 요소를 제어하고, AJAX를 통해 비동기적으로 데이터를 가져오고 업데이트하는 등의 작업을 수행할 수 있다. 이로 인해 프론트엔드 개발자들은 서버와의 상호작용이나 데이터 처리를 클라이언트 측에서 직접 처리할 수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 프론트엔드 프레임워크와 라이브러리들이 발전하면서 동적인 웹 애플리케이션 개발을 위한 다양한 선택지가 생겨났다. 대표적인 예시로는 React, Vue.js, Angular 등이 있다. 이러한 프론트엔드 프레임워크들은 가상 DOM을 활용하여 UI 컴포넌트를 동적으로 조작하고 업데이트할 수 있게 해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, RESTful API를 활용하여 클라이언트와 서버 간의 데이터 통신을 처리하는 방식도 널리 사용되고 있다. 이를 통해 클라이언트는 데이터를 비동기적으로 요청하고 서버로부터 데이터를 받아와 동적으로 웹 페이지를 업데이트할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 동적 웹 개발 방법들은 프론트엔드 개발자가 독립적으로 서버와 상호작용하고 데이터 처리를 수행할 수 있는 환경을 제공한다.&lt;/p&gt;</description>
      <category>Java</category>
      <category>HTML</category>
      <category>Java</category>
      <category>JSP</category>
      <category>JSTL</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/206</guid>
      <comments>https://fromnowwon.tistory.com/entry/jsp-jstl#entry206comment</comments>
      <pubDate>Sun, 9 Jul 2023 15:15:02 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 배열 중복 제거 시 정렬을 먼저 하는 이유</title>
      <link>https://fromnowwon.tistory.com/entry/algorism-sort-array</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;배열에서 중복된 값을 제거하기 위해서는 일반적으로 우선 배열을 정렬한다. 오름차순 정렬을 하면 중복된 값들이 인접한 위치에 모여 중복을 쉽게 찾을 수 있기 때문이다. 예를 들어, 정렬되지 않은 배열에서 중복을 찾으려면 배열의 모든 요소를 하나씩 비교해야 한다. 하지만 정렬된 배열에서는 중복된 값들이 연속해서 나타나기 때문에 중복을 찾는 과정이 간단해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국은 시간 복잡도를 줄이기 위함이다. 정렬된 배열에서 중복을 찾는 것은 인접한 값들만을 비교하면 되기 때문에 추가적인 반복문이나 자료구조를 사용할 필요가 없어진다. 반면, 정렬되지 않은 배열에서 중복을 찾으려면 모든 요소를 비교해야 하므로 시간 복잡도가 크게 증가할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-3749995100298532&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 주어진 배열이 [4, 2, 1, 2, 4, 3, 1]이라고 가정해 보자. 이 배열을 오름차순으로 정렬하면 [1, 1, 2, 2, 3, 4, 4]가 된다. 이제 중복을 제거하기 위해 인접한 값들을 비교하면서 중복된 값을 제거한다. [1, 1, 2, 2, 3, 4, 4]에서 중복된 값은 [1, 2, 4]입니다. 따라서 중복을 제거한 배열은 [1, 2, 3, 4]가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬과 중복 제거를 한 번에 처리하는 파이썬 예제 코드는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;def remove_duplicates(arr):
    arr.sort()  # 주어진 배열을 오름차순으로 정렬한다.

    n = len(arr)
    if n == 0 or n == 1:
        return arr  # 배열에 중복된 값이 없거나 하나밖에 없다면 그대로 반환한다.

    # 중복을 제거하는 과정
    j = 0
    for i in range(n - 1):
        if arr[i] != arr[i + 1]:
            arr[j] = arr[i]
            j += 1

    arr[j] = arr[n - 1]
    return arr[:j + 1]  # 중복이 제거된 배열을 반환한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬에서는 정렬을 수행하기 위해 &lt;code&gt;sort()&lt;/code&gt; 함수를 사용한다. 그러나 입력으로 주어진 배열이 이미 정렬되어 있는 경우, 당연히 정렬 과정이 생략된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 &lt;code&gt;sort()&lt;/code&gt; 함수도 정렬을 수행하는 과정에서 시간 복잡도를 가진다. &lt;code&gt;sort()&lt;/code&gt; 함수를 사용하여 배열을 정렬하는 과정에서 소요되는 시간 복잡도는 O(n log n)이다. 일반적인 정렬 알고리즘인 퀵소트(Quicksort)나 머지소트(Mergesort)는 평균적으로 O(n log n)의 시간 복잡도를 가지며, 힙소트(Heapsort)는 항상 O(n log n)의 시간 복잡도를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 중복을 제거하는 과정은 O(n)의 시간 복잡도를 가지고, &lt;code&gt;sort()&lt;/code&gt; 함수는 O(n log n)의 시간 복잡도를 가진다. 전체 코드의 빅오 시간 복잡도를 구할 때에는 더 큰 시간 복잡도를 기준으로 한다. 따라서 전체적인 시간 복잡도는 O(n log n)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Data Structure &amp;amp; Algorithm</category>
      <category>배열</category>
      <category>빅오</category>
      <category>시간복잡도</category>
      <category>정렬</category>
      <category>중복제거</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/205</guid>
      <comments>https://fromnowwon.tistory.com/entry/algorism-sort-array#entry205comment</comments>
      <pubDate>Wed, 5 Jul 2023 21:41:31 +0900</pubDate>
    </item>
    <item>
      <title>[React] onClick 이벤트 핸들러에 함수 전달하는 방법</title>
      <link>https://fromnowwon.tistory.com/entry/react-onClick</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리액트에서 onClick은 이벤트 핸들러 중 하나로서, 마우스 클릭 이벤트에 응답하여 실행되는 콜백 함수이다. 보통 버튼이나 링크와 같은 요소에 onClick 이벤트 핸들러를 등록하여 해당 요소를 클릭했을 때 원하는 동작을 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-3749995100298532&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;onclick-이벤트-핸들러에-함수를-전달하는-방법&quot; data-ke-size=&quot;size26&quot;&gt;onClick 이벤트 핸들러에 함수를 전달하는 방법&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;onClick prop에 함수 이름만을 전달&lt;/li&gt;
&lt;li&gt;예시: &lt;b&gt;&lt;code&gt;&amp;lt;button onClick={handleClick}&amp;gt;클릭&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;클릭 이벤트가 발생하면 &lt;b&gt;&lt;code&gt;handleClick&lt;/code&gt;&lt;/b&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;onClick prop에 익명 함수를 전달&lt;/li&gt;
&lt;li&gt;예시: &lt;b&gt;&lt;code&gt;&amp;lt;button onClick={() =&amp;gt; { console.log('클릭되었습니다.'); }}&amp;gt;클릭&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/b&gt;&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;함수 호출 결과를 onClick prop에 전달하는 것은 일반적으로 원하는 동작을 수행하지 못하므로 권장되지 않음&lt;/li&gt;
&lt;li&gt;예시: &lt;b&gt;&lt;code&gt;&amp;lt;button onClick={handleClick()}&amp;gt;클릭&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;위의 예시는 클릭 이벤트가 발생하기 전에 &lt;b&gt;&lt;code&gt;handleClick&lt;/code&gt;&lt;/b&gt; 함수가 호출되고, 함수 호출 결과가 onClick 이벤트 핸들러로 전달되며, 이는 원하는 동작을 수행하지 않을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 함수 이름이나 익명 함수를 onClick 이벤트 핸들러로 전달하는 것이 일반적인 방법이다. 이를 통해 클릭 이벤트 발생 시 원하는 함수가 실행되도록 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;코드-예제&quot; data-ke-size=&quot;size26&quot;&gt;코드 예제&lt;/h2&gt;
&lt;h3 id=&quot;함수-이름을-전달-함수-자체를-전달&quot; data-ke-size=&quot;size23&quot;&gt;1. 함수 이름을 전달 (함수 자체를 전달)&lt;/h3&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;Hamburger
	onClick={isBurgerMenuActive ? handleToCloseMenu : handleToOpenMenu}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 경우에는 &lt;b&gt;&lt;code&gt;onClick&lt;/code&gt;&lt;/b&gt; 이벤트가 발생했을 때, &lt;code&gt;isBurgerMenuActive&lt;/code&gt;가 참이면 &lt;b&gt;&lt;code&gt;handleToCloseMenu&lt;/code&gt;&lt;/b&gt; 함수를 호출하고, 그렇지 않으면 &lt;b&gt;&lt;code&gt;handleToOpenMenu&lt;/code&gt;&lt;/b&gt; 함수를 호출한다. 여기서 주의할 점은 함수 자체를 전달한다는 것이다. &lt;code&gt;handleToCloseMenu&lt;/code&gt;와 &lt;code&gt;handleToOpenMenu&lt;/code&gt;는 함수 자체를 가리키는 것이므로, 함수가 바로 실행되는 것이 아니라 이벤트가 발생했을 때 클릭 이벤트 핸들러 내에서 해당 함수를 호출하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드에서 &lt;b&gt;&lt;code&gt;onClick&lt;/code&gt;&lt;/b&gt; prop은 &lt;b&gt;&lt;code&gt;handleToCloseMenu&lt;/code&gt;, &lt;code&gt;handleToOpenMenu&lt;/code&gt;&lt;/b&gt; 함수를 이벤트 핸들러로 설정한다. 이렇게 작성된 경우, Hamburger 아이콘을 클릭했을 때 &lt;b&gt;&lt;code&gt;handleToCloseMenu&lt;/code&gt;&lt;/b&gt;혹은&lt;b&gt;&lt;code&gt;handleToOpenMenu&lt;/code&gt;&lt;/b&gt; 함수가 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 실행 순서&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Hamburger 컴포넌트를 렌더링 한다.&lt;/li&gt;
&lt;li&gt;onClick prop에 조건 연산자(&lt;b&gt;&lt;code&gt;isBurgerMenuActive ? handleToCloseMenu : handleToOpenMenu&lt;/code&gt;&lt;/b&gt;)를 사용하여 이벤트 핸들러를 선택한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;isBurgerMenuActive&lt;/code&gt;&lt;/b&gt; 값이 참인 경우 &lt;b&gt;&lt;code&gt;handleToCloseMenu&lt;/code&gt;&lt;/b&gt; 함수가 onClick 이벤트 핸들러로 설정된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;isBurgerMenuActive&lt;/code&gt;&lt;/b&gt; 값이 거짓인 경우 &lt;b&gt;&lt;code&gt;handleToOpenMenu&lt;/code&gt;&lt;/b&gt; 함수가 onClick 이벤트 핸들러로 설정된다.&lt;/li&gt;
&lt;li&gt;클릭 이벤트가 발생하면 해당하는 함수가 실행된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;익명-함수를-사용하여-전달&quot; data-ke-size=&quot;size23&quot;&gt;2. 익명 함수를 사용하여 전달&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 함수를 호출하면서 반환값을 전달해야 할 때는 즉시 실행되는 즉시 실행 함수(IIFE, Immediately Invoked Function Expression)를 사용한다. 즉시 실행 함수는 익명 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드는 익명 함수를 사용하여 클릭 이벤트 핸들러를 정의한 예시이다.&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;Hamburger
	onClick={() =&amp;gt; {
		if (isBurgerMenuActive) {
			handleToCloseMenu();
		} else {
			handleToOpenMenu();
		}
	}}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 주어진 조건(&lt;b&gt;&lt;code&gt;isBurgerMenuActive&lt;/code&gt;&lt;/b&gt;)에 따라 클릭 이벤트 핸들러를 익명 함수로 작성했다. 익명 함수 내부에서 조건문을 사용하여 &lt;b&gt;&lt;code&gt;isBurgerMenuActive&lt;/code&gt;&lt;/b&gt; 값에 따라 &lt;b&gt;&lt;code&gt;handleToCloseMenu&lt;/code&gt;&lt;/b&gt; 또는 &lt;b&gt;&lt;code&gt;handleToOpenMenu&lt;/code&gt;&lt;/b&gt; 함수를 호출하도록 처리했다. 이렇게 익명 함수를 사용하면 조건에 따라 동적으로 함수를 호출할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명 함수를 사용하면 익명 함수의 정의만 전달되므로 익명 함수 내부에 있는 함수는 클릭 이벤트가 발생했을 때 실행되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 실행 순서&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Hamburger 컴포넌트를 렌더링 합니다. onClick prop에 익명 함수를 전달한다.&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;b&gt;&lt;code&gt;isBurgerMenuActive&lt;/code&gt;&lt;/b&gt; 값에 따라 분기한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;isBurgerMenuActive&lt;/code&gt;&lt;/b&gt; 값이 참인 경우 &lt;b&gt;&lt;code&gt;handleToCloseMenu&lt;/code&gt;&lt;/b&gt; 함수가 호출된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;isBurgerMenuActive&lt;/code&gt;&lt;/b&gt; 값이 거짓인 경우 &lt;b&gt;&lt;code&gt;handleToOpenMenu&lt;/code&gt;&lt;/b&gt; 함수가 호출된다.&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;&lt;b&gt;&lt;code&gt;handleToCloseMenu&lt;/code&gt;&lt;/b&gt; 함수 또는 &lt;b&gt;&lt;code&gt;handleToOpenMenu&lt;/code&gt;&lt;/b&gt; 함수가 실행된다.&lt;/li&gt;
&lt;li&gt;각 함수는 클릭 이벤트에 대한 응답으로 원하는 동작을 수행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;함수-호출-결과를-전달&quot; data-ke-size=&quot;size23&quot;&gt;3. 함수 호출 결과를 전달&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 때로는 함수를 호출한 결과를 onClick에 전달하려는 실수를 하기도 한다. 예를 들어, 아래와 같이 작성하는 경우가 있다.&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;Hamburger
	onClick={isBurgerMenuActive ? handleToCloseMenu() : handleToOpenMenu()}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 경우에는 &lt;b&gt;&lt;code&gt;onClick&lt;/code&gt;&lt;/b&gt; 이벤트가 발생했을 때, &lt;code&gt;isBurgerMenuActive&lt;/code&gt;가 참이면 &lt;code&gt;handleToCloseMenu()&lt;/code&gt;를 호출하고, 그렇지 않으면 &lt;code&gt;handleToOpenMenu()&lt;/code&gt;를 호출한다. 이 경우 함수를 호출한 결괏값을 전달하게 되는데, 이는 실제로 이벤트 핸들러에 함수가 아닌 &lt;b&gt;함수의 반환값을 전달하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 호출하면서 반환값을 전달하므로, 클릭 이벤트 핸들러가 바인딩될 때 한 번 호출되는 것이 아니라, 렌더링 시에 매번 함수가 호출되게 된다. 따라서, 괄호 없이 함수 이름만 전달하는 것이 올바른 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 실행 순서&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Hamburger 컴포넌트를 렌더링 한다.&lt;/li&gt;
&lt;li&gt;onClick prop에 조건 연산자를 사용하여 이벤트 핸들러를 선택한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;isBurgerMenuActive&lt;/code&gt;&lt;/b&gt; 값이 참인 경우 &lt;b&gt;&lt;code&gt;handleToCloseMenu()&lt;/code&gt;&lt;/b&gt; 함수를 호출하여 실행 결과를 onClick 이벤트 핸들러로 설정한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;isBurgerMenuActive&lt;/code&gt;&lt;/b&gt; 값이 거짓인 경우 &lt;b&gt;&lt;code&gt;handleToOpenMenu()&lt;/code&gt;&lt;/b&gt; 함수를 호출하여 실행 결과를 onClick 이벤트 핸들러로 설정한다.&lt;/li&gt;
&lt;li&gt;Hamburger 아이콘을 렌더링 할 때 함수가 호출되고 실행되며, 그 결과가 onClick 이벤트 핸들러로 전달된다.&lt;/li&gt;
&lt;li&gt;클릭 이벤트가 발생하면 함수 호출 결과가 실행된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 이벤트 핸들러에는 함수 자체를 전달하는 것이 일반적이며, 함수를 호출하면서 반환값을 전달해야 할 때는 즉시 실행 함수 등을 사용하는 게 일반적이다.&lt;/p&gt;</description>
      <category>React</category>
      <category>onClick</category>
      <category>react</category>
      <category>익명함수</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/204</guid>
      <comments>https://fromnowwon.tistory.com/entry/react-onClick#entry204comment</comments>
      <pubDate>Mon, 3 Jul 2023 14:04:20 +0900</pubDate>
    </item>
    <item>
      <title>&amp;lt;!DOCTYPE&amp;gt; 선언 이유와 예시 코드</title>
      <link>https://fromnowwon.tistory.com/entry/html-DOCTYPE</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt;은 HTML 문서의 첫 줄에 위치한 선언문이다. &quot;Document Type Declaration&quot;의 약자로, 웹 브라우저에게 해당 문서가 어떤 버전의 HTML이나 XHTML로 작성되었는지 알려준다. 이 선언문은 웹 브라우저가 문서를 올바르게 해석하고 렌더링 하는 데 필요한 정보를 제공한다.&lt;/p&gt;
&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;HTML5를 사용하여 작성된 문서&lt;/b&gt;임을 나타낸다. HTML5는 최신 버전의 HTML 표준으로서, 다양한 기능과 태그를 지원하며 웹 페이지를 보다 구조화된 형식으로 작성할 수 있게 해준다.&amp;nbsp;&lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문은 웹 브라우저에게 문서를 어떻게 해석해야 하는지 알려주는 중요한 역할을 한다. 정확한 선언문을 사용하면 웹 페이지가 일관성 있게 표시되고 웹 브라우저 간의 호환성 문제를 최소화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문은 웹 브라우저에게 &quot;이 웹 페이지는 어떤 버전의 HTML을 사용하여 작성되었고 어떻게 해석해야 하는지 알려줘&quot;라고 말하는 것과 같다. 웹 브라우저는 웹 페이지를 읽어 들일 때 이 선언문을 확인하여 페이지를 올바르게 해석하고 표시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;웹-기술-발전과-doctype-선언문&quot; data-ke-size=&quot;size26&quot;&gt;웹 기술 발전과 &amp;lt;!DOCTYPE&amp;gt; 선언문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 선언문이 필요한 이유는 웹 기술이 발전하면서 HTML의 버전이나 규칙들도 계속 업데이트되고 변경되었기 때문이다. 각 버전마다 새로운 태그와 기능이 추가되거나 수정되기도 한다. 따라서 웹 브라우저는 페이지를 열기 전에 해당 페이지가 어떤 버전의 HTML을 사용하는지 알아야 한다. 이를 위해 &lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올바른 &lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문을 사용하면 웹 브라우저가 문서를 올바르게 해석하고 예상대로 표시할 수 있다. 그렇지 않을 경우 페이지의 레이아웃이 깨지거나 기능이 동작하지 않을 수 있다. 따라서 &lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문은 웹 페이지의 호환성과 일관성을 유지하기 위해 매우 중요한 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-3749995100298532&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;doctype-선언문을-작성해야-하는-이유-요약&quot; data-ke-size=&quot;size26&quot;&gt;&amp;lt;!DOCTYPE&amp;gt; 선언문을 작성해야 하는 이유 요약&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;올바른 버전 지정: 웹 브라우저에게 해당 웹 페이지가 어떤 버전의 HTML을 사용하여 작성되었는지 알려준다. 이는 웹 브라우저가 페이지를 올바르게 해석하고 표시하는 데 필요하다.&lt;/li&gt;
&lt;li&gt;호환성 유지: &lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문을 통해 웹 페이지가 다른 웹 브라우저나 기기에서도 일관되게 표시되도록 도와준다. 올바른 선언문을 사용하면 호환성 문제를 최소화할 수 있다.&lt;/li&gt;
&lt;li&gt;문서 구조 파악: 웹 브라우저는 &lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문을 통해 문서 구조를 파악하고 이에 따라 페이지를 렌더링 한다. 이는 웹 페이지의 구성과 레이아웃을 정확하게 표시하는 데 중요하다.&lt;/li&gt;
&lt;li&gt;표준 준수: HTML 표준은 지속적으로 발전하고 변경되는데, &lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문은 해당 표준을 준수하기 위해 필요하다. 올바른 선언문을 작성함으로써 최신 기술과 규칙을 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;오류 방지: 올바른 &lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문을 작성하면 문서 구문 오류를 방지할 수 있다. 웹 브라우저는 선언문을 통해 페이지를 정확하게 해석하고 오류를 예방할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;doctype-선언문의-예시-코드&quot; data-ke-size=&quot;size26&quot;&gt;&amp;lt;!DOCTYPE&amp;gt; 선언문의 예시 코드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML5의 경우, 다음과 같이 &lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt; 선언문을 작성한다.&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;웹 페이지 제목&amp;lt;/title&amp;gt;
    &amp;lt;!-- 이하의 코드는 head 태그 내부에 작성 --&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;!-- 이하의 코드는 body 태그 내부에 작성 --&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 HTML5로 작성된 웹 페이지임을 나타낸다. 웹 브라우저는 이 선언문을 통해 해당 페이지를 HTML5로 해석하고 표시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이전 버전의 HTML인 XHTML 1.0 Transitional을 사용한다면, 다음과 같이 작성할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;&amp;lt;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;gt;&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 XHTML 1.0 Transitional 버전으로 작성된 웹 페이지임을 나타내며, 해당 버전의 DTD(Document Type Definition) 파일을 참조하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선언문은 각 HTML 버전에 따라 약간씩 다를 수 있으며, 문서가 어떤 버전의 HTML을 사용하는지 정확히 명시해야 한다. 따라서 웹 페이지를 작성할 때 적절한 버전의 선언문을 사용하는 것이 중요하다.&lt;/p&gt;</description>
      <category>HTML</category>
      <category>DOCTYPE</category>
      <category>HTML</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/203</guid>
      <comments>https://fromnowwon.tistory.com/entry/html-DOCTYPE#entry203comment</comments>
      <pubDate>Mon, 3 Jul 2023 13:08:47 +0900</pubDate>
    </item>
    <item>
      <title>인터페이스(Interface)란? 인터페이스 정의서로 협업하기</title>
      <link>https://fromnowwon.tistory.com/entry/interface</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 백엔드와 프론트엔드가 소통하기 위한 규약이라고 생각하면 된다. 백엔드는 데이터를 처리하고 비즈니스 로직을 구현하며 서버와의 통신을 담당한다. 이러한 백엔드의 기능들은 프론트엔드에 정보와 기능을 제공하는 데 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 일종의 계약서다. 이 계약서에는 백엔드가 어떤 데이터를 제공하고 어떤 기능을 제공하는지에 대한 설명이 포함된다. 프론트엔드 개발자는 이 계약서를 참고하여 필요한 데이터나 기능을 요청하고, 그에 맞는 방식으로 백엔드와 소통한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 구체적으로 예를 들어 설명하면, 백엔드에서는 특정 API를 제공하며, 프론트에서는 이 API를 통해 데이터를 요청하거나 서버에 특정 작업을 요청할 수 있다. 이때 API의 형식이나 파라미터, 응답 형식 등이 인터페이스의 일부가 된다. 프론트엔드 개발자는 백엔드의 인터페이스를 이해하고 해당 API를 호출하거나 데이터를 요청함으로써 필요한 정보를 얻거나 작업을 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-3749995100298532&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;인터페이스-정의서&quot; data-ke-size=&quot;size26&quot;&gt;인터페이스 정의서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 인터페이스 정의서는 백엔드 개발자가 작성하여 프론트엔드 개발자 또는 다른 팀원들에게 전달한다. 인터페이스 정의서는 백엔드 개발자가 API의 명세와 기능을 명확하게 정의하고 문서화하여 다른 팀원들이 이를 이해하고 활용할 수 있도록 돕는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드 개발자는 자신이 개발한 API의 엔드포인트, 요청 형식, 응답 형식, 파라미터, 응답 상태 코드 등을 정확히 기술하고 문서화해야 한다. 이렇게 작성된 인터페이스 정의서를 프론트엔드 개발자에게 제공함으로써 백엔드와 프론트엔드 간의 원활한 소통과 협업이 가능해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 인터페이스 정의서는 백엔드 개발자들이 작성하여 다른 팀원들에게 전달하는 중요한 문서라고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스 정의서는 일반적으로 다음과 같은 정보를 포함할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;API 엔드포인트와 HTTP 메서드&lt;/b&gt;: 백엔드가 제공하는 각 API의 엔드포인트 경로와 해당 API를 호출하기 위해 사용해야 하는 HTTP 메서드(GET, POST, PUT, DELETE 등)를 명시한다. 예를 들어, &lt;b&gt;&lt;code&gt;/login&lt;/code&gt;&lt;/b&gt; 경로에 POST 요청을 보내면 로그인이 처리되는 API라면 해당 정보를 정의한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;요청과 응답의 데이터 형식&lt;/b&gt;: 백엔드와 프론트엔드 간의 데이터 교환 형식을 정의한다. 예를 들어, 요청과 응답에 JSON 형식을 사용한다면, JSON 객체의 필드와 그 형식을 명시한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파라미터&lt;/b&gt;: 각 API에 필요한 파라미터와 그에 대한 설명을 포함한다. 파라미터는 API 호출 시에 전달되는 데이터로, 예를 들어 로그인 API에서는 사용자명과 비밀번호가 필요한데, 이러한 파라미터들을 정의한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답 상태 코드&lt;/b&gt;: 백엔드에서 API 호출에 대한 응답으로 반환하는 상태 코드를 설명한다. 예를 들어, 성공적인 응답에는 200 OK 상태 코드를 사용하고, 인증 오류에는 401 Unauthorized 상태 코드를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에러 처리&lt;/b&gt;: API 호출 시 발생할 수 있는 예외 상황과 에러 처리 방법을 설명한다. 예를 들어, 유효하지 않은 요청이 들어올 경우 어떤 상태 코드를 반환하고 어떤 에러 메시지를 제공해야 하는지를 정의한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;인터페이스-정의서-예시&quot; data-ke-size=&quot;size26&quot;&gt;인터페이스 정의서 관리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 표에는 API의 엔드포인트, HTTP 메서드, 요청 파라미터, 응답 데이터 형식, 그리고 응답 상태 코드 등을 열과 행으로 구성하여 정리되어 있다. 이렇게 작성된 인터페이스 정의서를 엑셀로 관리하면 정보를 쉽게 확인하고 업데이트할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 105px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 20px;&quot;&gt;API 엔드포인트&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 20px;&quot;&gt;HTTP 메서드&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 20px;&quot;&gt;요청 파라미터&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 20px;&quot;&gt;응답 데이터 형식&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 20px;&quot;&gt;응답 상태 코드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;/users&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;GET&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;JSON&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;200: 성공, 404: 사용자 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;/users/{id}&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;GET&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;id (파라미터 타입: 정수)&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;JSON&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;200: 성공, 404: 사용자 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;/users&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;POST&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;JSON 객체&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;201: 생성됨, 400: 잘못된 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;/users/{id}&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;PUT&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;id (파라미터 타입: 정수)&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;JSON 객체&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;200: 성공, 404: 사용자 없음, 400: 잘못된 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;/users/{id}&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;DELETE&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;id (파라미터 타입: 정수)&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;204: 삭제됨, 404: 사용자 없음, 400: 잘못된 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 인터페이스 정의서는 다양한 형식으로 관리될 수 있다. 그중에서도 Swagger는 인기 있는 도구 중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger는 API 문서를 작성하고 관리하기 위한 프레임워크로, 개발자들이 API에 대한 정보를 문서화하고 시각적으로 확인할 수 있도록 도와준다. Swagger를 사용하면 API의 엔드포인트, 요청 및 응답 형식, 파라미터, 응답 상태 코드 등을 정의하고 문서화할 수 있다. Swagger를 활용하면 자동으로 API 문서를 생성하고 인터랙티브 한 방식으로 사용할 수 있는 UI를 제공해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뿐만 아니라, 다른 형식으로는 Markdown이나 HTML 문서로 작성하여 관리하기도 한다. Markdown은 간단하고 가독성이 좋은 문서 형식이며, HTML은 더욱 정교한 포맷팅과 스타일링을 제공할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 형식을 선택할지는 개발자의 선호도와 팀의 요구사항에 따라 다를 수 있다. Swagger는 많은 개발자들에게 인기가 있으며, API 문서를 표준화하고 관리하기에 효과적인 도구로 사용된다. 하지만 직접 문서를 작성하는 것도 일반적인 방법이다. 형식보다 중요한 점은 인터페이스 정의서가 명확하고 업데이트되며, 팀원들이 쉽게 접근하고 이해할 수 있는 형식으로 관리되어야 한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;인터페이스를-통한-협업&quot; data-ke-size=&quot;size26&quot;&gt;인터페이스를 통한 협업&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 인터페이스 정의서를 기반으로 백엔드와 프론트엔드가 소통하고 작업하는 과정을 예시 코드를 통해 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;1) 백엔드 개발자는 인터페이스 정의서를 작성한다. 이를 통해 백엔드 개발자는 API의 엔드포인트, HTTP 메서드, 요청 파라미터, 응답 데이터 형식, 응답 상태 코드 등을 정확히 명시한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 프론트엔드 개발자는 백엔드 개발자가 작성한 인터페이스 정의서를 받아 확인한다. 이를 통해 어떤 API가 제공되는지, 요청과 응답의 형식은 어떤지 등을 파악할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1687417553449&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fetch('/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    username: '사용자명',
    password: '비밀번호',
  }),
})
  .then(response =&amp;gt; response.text())
  .then(data =&amp;gt; {
    // 로그인 요청에 대한 응답 처리
    console.log(data);
  })
  .catch(error =&amp;gt; console.error(error));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3)&amp;nbsp;프론트엔드 개발자는 인터페이스 정의서를 참고하여 실제로 API를 호출하고 요청을 보낸다. 예를 들어, 프론트엔드에서 로그인 기능을 구현하기 위해 &lt;b&gt;&lt;code&gt;/login&lt;/code&gt;&lt;/b&gt; 경로에 POST 요청을 보낼 수 있다. 로그인에 필요한 사용자명과 비밀번호를 JSON 형식으로 전송하고, 이후 응답을 받아와 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 백엔드에서 로그인 요청 처리하기: 백엔드에서는 &lt;code&gt;/login&lt;/code&gt; 경로에 대한 POST 요청에 대한 처리를 수행한다. 해당 메서드는 받아온 사용자 정보를 검증하고 인증 과정을 수행한 뒤, 결과에 따라 적절한 응답을 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1687417636527&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RestController
public class AuthController {

    @PostMapping(&quot;/login&quot;)
    public ResponseEntity&amp;lt;String&amp;gt; login(@RequestBody LoginRequest request) {
        // 받아온 사용자 정보를 검증하고 인증 과정을 수행하는 코드
        // ...

        if (isValidCredentials(request.getUsername(), request.getPassword())) {
            // 인증이 성공한 경우 토큰을 생성하거나 세션을 유지하는 등의 작업을 수행하는 코드
            // ...

            return ResponseEntity.ok(&quot;로그인 성공&quot;);
        } else {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(&quot;로그인 실패&quot;);
        }
    }

    // 다른 백엔드 기능들과 관련된 API들도 정의할 수 있음
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) 프론트엔드 개발자는 백엔드로부터 받은 응답을 처리한다. 예를 들어, 로그인 요청에 대한 응답으로 성공적인 로그인인지, 실패인지를 확인하고, 그에 따른 다음 동작을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같은 방식으로 프론트엔드와 백엔드는 인터페이스 정의서를 확인하고 작업을 진행함으로써 상호 간에 정확한 소통과 원활한 협업을 이루어낼 수 있다. 인터페이스 정의서는 두 팀 사이의 협업을 간소화하고 개발 작업의 일관성과 효율성을 향상하는 중요한 문서라고 볼 수 있다.&lt;/p&gt;</description>
      <category>협업</category>
      <category>SWAGGER</category>
      <category>인터페이스</category>
      <category>인터페이스 정의서</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/202</guid>
      <comments>https://fromnowwon.tistory.com/entry/interface#entry202comment</comments>
      <pubDate>Thu, 22 Jun 2023 16:09:35 +0900</pubDate>
    </item>
    <item>
      <title>빅오 표기법에 따른 파이썬 코드 예시</title>
      <link>https://fromnowwon.tistory.com/entry/python-bigO</link>
      <description>&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-3749995100298532&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20%;&quot;&gt;시간 복잡도&lt;/td&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;예시&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;리스트 인덱싱&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;인덱스를 통해 리스트의 요소에 접근하는 작업은 일정한 시간이 소요됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;O(logn)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;이진 탐색&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;정렬된 리스트에서 특정 값을 찾는 작업은 탐색 범위를 반으로 나누며, 탐색 속도가 로그에 비례&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;선형 탐색&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;리스트의 모든 요소를 한 번씩 확인하는 작업은 입력 크기에 비례하여 진행됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;O(nlogn)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;병합 정렬&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;리스트를 반으로 분할하고 재귀적으로 정렬하며, 분할된 부분 리스트를 병합하는 작업이 로그와 선형의 곱에 비례&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;O(n&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&amp;sup2;&lt;/span&gt;)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;이중 반복문&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;이중 반복문을 사용하여 리스트의 모든 요소 쌍을 확인하는 작업은 입력 크기의 제곱에 비례&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;O(2ⁿ)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;부분 집합 생성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;모든 부분 집합을 생성하기 위해 가능한 모든 조합을 확인하는 작업은 2의 입력 크기에 대한 지수적인 시간이 소요됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;O(n!) - n 팩토리얼 시간&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;순열 생성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;모든 가능한 순열을 생성하는 작업은 입력 크기에 대해 매우 큰 시간이 소요됨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;o1-상수-시간&quot; data-ke-size=&quot;size26&quot;&gt;1. O(1): 상수 시간&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(1) 시간 복잡도는 입력 크기에 관계없이 항상 일정한 실행 시간을 가지는 알고리즘을 의미한다. 즉, 입력의 크기에 관계없이 일정한 시간만큼의 연산을 수행한다. O(1) 알고리즘은 매우 효율적이며 실행 시간이 상수로 고정되어 있기 때문에 가장 이상적인 시간 복잡도이다.&lt;/p&gt;
&lt;h3 id=&quot;파이썬에서-o1-시간-복잡도를-가지는-경우&quot; data-ke-size=&quot;size23&quot;&gt;파이썬에서 O(1) 시간 복잡도 예:&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) 리스트, 튜플, 문자열 등의 인덱스로 요소에 접근하는 경우&lt;/h4&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;def get_first_element(lst):
    return lst[0]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 주어진 리스트에서 첫 번째 요소를 반환하는 함수다. 이 함수는 리스트의 크기에 관계없이 항상 첫 번째 요소를 반환하는데, 이 연산은 상수 시간에 이루어진다. 즉, 입력 리스트의 크기가 어떻든지 상관없이 항상 동일한 실행 시간을 가진다. 따라서 이 함수의 시간 복잡도는 O(1)이다. 파이썬의 시퀀스 자료형에서는 인덱스를 사용하여 특정 위치에 있는 요소에 접근하는 연산이 O(1) 시간에 수행된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 사전(Dictionary)에서 키(Key)를 사용하여 값(Value)에 접근하는 경우&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 사전은 해시 테이블을 기반으로 구현되어 있어서 특정 키를 사용하여 값을 찾는 연산이 평균적으로 O(1) 시간에 수행된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) 산술 연산과 비트 연산&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 산술 연산자와 비트 연산자는 입력의 크기와 상관없이 항상 일정한 시간에 수행되므로 O(1) 시간 복잡도를 가진다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4) 객체의 메서드 호출&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 메서드 호출은 해당 메서드의 구현에 따라 다르지만, 대부분의 경우 메서드 호출은 상수 시간에 수행된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5) 슬라이싱(Slicing)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 슬라이싱 연산은 원본 객체를 복사하지 않고 새로운 슬라이스 객체를 생성하기 때문에 O(1) 시간에 수행된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6) 크기가 고정된 작업&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 크기와 상관없이 항상 일정한 크기의 작업을 수행하는 경우, 해당 작업은 O(1) 시간에 수행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;ologn-로그-시간&quot; data-ke-size=&quot;size26&quot;&gt;2. O(logn): 로그 시간&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(logn) 시간 복잡도를 갖는 대표적인 예시로 이진 탐색(Binary Search) 알고리즘이 있다. 이진 탐색은 정렬된 리스트에서 특정 값을 찾는 알고리즘으로, 반씩 범위를 줄여가며 탐색을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진 탐색은 매 반복마다 탐색 범위를 절반으로 줄이므로, 입력 크기 n에 대해 O(logn)의 시간 복잡도를 가진다. 이 알고리즘은 정렬된 리스트에서 특정 값을 효율적으로 찾을 때 사용된다.&lt;/p&gt;
&lt;h3 id=&quot;예-이진-탐색-이진-트리-이진-힙-분할-정복-이진-검색-트리&quot; data-ke-size=&quot;size23&quot;&gt;예: 이진 탐색, 이진트리, 이진 힙, 분할 정복, 이진 검색 트리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 알고리즘은 입력의 크기에 따라 탐색 범위를 반으로 나누거나, 이진트리 구조를 활용하여 탐색을 효율적으로 수행한다. 이를 통해 O(logn)의 시간 복잡도를 달성할 수 있다.&lt;/p&gt;
&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;code&gt;arr&lt;/code&gt;에서 &lt;code&gt;target&lt;/code&gt; 값을 이진 탐색하여 해당 값의 인덱스를 반환하는 함수 예시&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;def binary_search(arr, target):
    low = 0 # 첫번째 인덱스로 초기화
    high = len(arr) - 1 # 마지막 인덱스로 초기화

    # 반복문을 통해 low와 high가 교차할 때까지 실행
    while low &amp;lt;= high:
        mid = (low + high) // 2
        # target 값과 mid 값이 같으면 mid가 target이므로 mid 반환
        if arr[mid] == target:
            return mid
        # target이 mid보다 크면 low를 mid+1로 업데이트하여 범위를 오른쪽으로 줄인다.
        elif arr[mid] &amp;lt; target:
            low = mid + 1
        # target이 mid보다 작으면 high를 mid-1로 업데이트하여 범위를 왼쪽으로 줄인다.
        else:
            high = mid - 1
    # target이 없는 경우 -1 반환
    return -1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;on-선형-시간&quot; data-ke-size=&quot;size26&quot;&gt;3. O(n): 선형 시간&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 크기에 비례하여 선형적으로 연산이 증가한다. 입력 크기가 두 배로 늘어나면 연산도 두 배로 증가한다. 예를 들어, 리스트의 모든 요소를 한 번씩 확인하는 경우를 말한다.&lt;/p&gt;
&lt;h3 id=&quot;예-리스트의-모든-요소를-출력하는-경우&quot; data-ke-size=&quot;size23&quot;&gt;예: 리스트의 모든 요소를 출력하는 경우&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트의 크기에 비례하여 모든 요소를 한 번씩 출력하기 때문에 시간 복잡도는 O(n)이다.&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;def print_list(lst):
    for item in lst:
        print(item)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;onlogn-선형-로그-시간&quot; data-ke-size=&quot;size26&quot;&gt;4. O(nlogn): 선형 로그 시간&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 크기에 비례하여 연산이 증가하지만, 로그 함수의 형태로 증가한다. 입력 크기가 두 배로 늘어나면 연산은 약간 더 많아지지만 비례적으로 늘어나지 않는다. 정렬 알고리즘인 병합 정렬과 퀵 정렬이 이에 해당한다.&lt;/p&gt;
&lt;h3 id=&quot;예-정렬-알고리즘-병합-정렬-퀵-정렬-등&quot; data-ke-size=&quot;size23&quot;&gt;예: 정렬 알고리즘 (병합 정렬, 퀵 정렬 등)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병합 정렬은 리스트를 반으로 나누고, 나누어진 부분 리스트를 정렬한 후 병합하는 과정을 재귀적으로 수행한다. 이때, 리스트를 나누는 과정은 O(logn)이며, 각 부분 리스트를 병합하는 과정은 O(n)이다. 따라서 전체 시간 복잡도는 O(nlogn)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;병합 정렬 알고리즘을 재귀적으로 구현한 예시 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 정렬된 리스트 반환
def merge_sort(lst):
    # 리스트의 길이가 1 이하인 경우 그대로 반환
    if len(lst) &amp;lt;= 1:
        return lst
    # 리스트를 반으로 나누어 재귀적으로 호출
    mid = len(lst) // 2
    left = merge_sort(lst[:mid]) # 첫 번째부터 중간까지의 요소
    right = merge_sort(lst[mid:]) # 중간부터 마지막까지의 요소
    return merge(left, right) # 병합

# 두 개의 정렬된 리스트 병합
def merge(left, right):
    result = []
    while left and right: # 리스트가 모두 비어있지 않은 동안 반복문을 실행
        # left와 right의 첫 번째 요소를 비교하고, 작은 값을 result에 추가
        if left[0] &amp;lt; right[0]:
            # 추가한 요소는 원본 리스트에서 제거
            result.append(left.pop(0))
        else:
            result.append(right.pop(0))
    # 남아있는 리스트의 모든 요소를 result에 추가
    if left:
        result.extend(left)
    if right:
        result.extend(right)
    # 정렬이 완료된 result 리스트 반환
    return result&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;※ 파이썬의 &lt;code&gt;sort()&lt;/code&gt;는 O(nlogn)이다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 &lt;code&gt;sort()&lt;/code&gt; 함수가 O(nlogn)인 이유는 주로 퀵 정렬(Quick Sort) 알고리즘을 기반으로 구현되어 있기 때문이다. 퀵 정렬은 분할 정복(Divide and Conquer) 방법을 사용하여 리스트를 정렬한다. 이 알고리즘은 다음과 같은 과정으로 진행된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;리스트에서 하나의 원소를 기준으로 선택한다. 이를 피벗(Pivot)이라고 한다.&lt;/li&gt;
&lt;li&gt;피벗을 기준으로 작은 값은 왼쪽으로, 큰 값은 오른쪽으로 분할한다.&lt;/li&gt;
&lt;li&gt;분할된 두 개의 부분 리스트에 대해 재귀적으로 퀵 정렬을 수행한다.&lt;/li&gt;
&lt;li&gt;재귀 호출을 통해 정렬된 부분 리스트들을 병합한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 평균적으로 각 분할 단계에서 피벗을 중심으로 리스트를 대략 반으로 나눌 수 있다. 이 때문에 퀵 정렬은 평균적으로 O(nlogn)의 시간 복잡도를 가지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 최악의 경우, 퀵 정렬은 이미 정렬된 리스트에서 가장 작거나 가장 큰 요소를 피벗으로 선택하는 경우에는 분할이 제대로 이루어지지 않아 시간 복잡도가 O(n^2)까지 증가할 수 있다. 이러한 최악의 경우를 피하기 위해 피벗을 랜덤 하게 선택하거나, 최적화된 피벗 선택 방법을 사용하는 것이 일반적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 &lt;code&gt;sort()&lt;/code&gt; 함수는 퀵 정렬을 기반으로 하되, 최적화된 알고리즘과 피벗 선택 방법을 사용하여 평균적으로 O(nlogn)의 성능을 제공한다. 그렇기 때문에 대부분의 경우 &lt;code&gt;sort()&lt;/code&gt; 함수는 효율적인 정렬을 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;on2-이차-시간&quot; data-ke-size=&quot;size26&quot;&gt;5. O(n&amp;sup2;): 이차 시간&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 크기의 제곱에 비례하여 연산이 증가한다. 입력 크기가 두 배로 늘어나면 연산은 네 배로 증가한다. 예를 들어, 이중 반복문을 사용하여 리스트의 모든 쌍을 확인하는 경우가 있다.&lt;/p&gt;
&lt;h3 id=&quot;예-이중-반복문을-사용하는-경우&quot; data-ke-size=&quot;size23&quot;&gt;예: 이중 반복문을 사용하는 경우&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중 반복문을 사용하여 리스트의 모든 쌍을 출력하는 경우, 외부 반복문은 n번 실행되고 내부 반복문은 n-1, n-2, &amp;hellip;, 2, 1번 실행됩니다. 따라서 전체 시간 복잡도는 약 n*(n-1)/2로 표현할 수 있으며, 이는 O(n^2)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이중 반복문 예시 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;def print_pairs(lst):
    for i in range(len(lst)):
        for j in range(i+1, len(lst)):
            print(lst[i], lst[j])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. O(2ⁿ): 지수 시간&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도가 O(2ⁿ)인 경우는 주로 부분집합(Subsets) 생성이나 조합적 문제에서 발생한다. 이러한 문제는 주어진 집합의 모든 부분집합 또는 가능한 조합을 생성해야 하기 때문에, 경우의 수가 2ⁿ 개인 지수적으로 증가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;집합의 모든 부분집합을 생성하는 예시 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1687415318730&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def generate_subsets(nums):
    subsets = []
    n = len(nums)

    # 0부터 2^n까지의 모든 숫자에 대해 반복
    for i in range(2 ** n):
        subset = []

        # 해당 비트가 1인 원소를 subset에 추가
        for j in range(n):
            if (i &amp;gt;&amp;gt; j) &amp;amp; 1:
                subset.append(nums[j])

        subsets.append(subset)

    return subsets&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 주어진 리스트 nums의 모든 부분집합을 생성하는 함수이다. 이중 반복문을 사용하여 0부터 2^n까지의 모든 숫자에 대해 비트 연산을 수행하고, 해당 비트가 1인 원소를 부분집합에 추가한다. 이를 통해 모든 가능한 부분집합을 생성하므로 시간 복잡도는 O(2ⁿ)이 된다.&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;7. O(n!): n 팩토리얼 시간&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n!은 n의 팩토리얼을 나타내며, n부터 1까지의 모든 자연수를 곱한 값을 의미한다. n이 증가할수록 시간이 기하급수적으로 증가한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;n! = n * (n-1) * (n-2) * ... * 2 * 1&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(n!) 시간 복잡도는 입력 크기 n에 대해 가능한 모든 순열을 생성하고 처리하는 경우에 해당한다. 예를 들어, n개의 요소로 이루어진 모든 순열을 구하는 경우, 시간 복잡도는 O(n!)이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n!은 매우 빠르게 증가하는 함수이기 때문에 n이 작을 때는 상대적으로 빠른 실행 시간을 갖지만, n이 커질수록 실행 시간이 급격하게 증가한다. 따라서 n! 시간 복잡도는 매우 큰 입력에 대해 비효율적이며, 일반적으로 효율적인 알고리즘을 설계하기 위해 피해야 한다.&lt;/p&gt;
&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;n 팩토리얼 시간 복잡도를 가지는 예시 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1687415376752&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def permutation(arr):
    if len(arr) == 1:
        return [arr]

    result = []
    for i in range(len(arr)):
        rest = arr[:i] + arr[i+1:]
        for p in permutation(rest):
            result.append([arr[i]] + p)

    return result&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 리스트 arr의 모든 순열을 반환하는 함수이다. 함수 내부에서 재귀적으로 순열을 생성하고, 각각의 순열은 원소 하나를 선택하고 나머지 원소들에 대해 순열을 생성하는 방식으로 구현되어 있다. 이러한 방식으로 모든 가능한 순열을 생성하므로 시간 복잡도는 O(n!)이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n 팩토리얼 시간 복잡도를 가지는 알고리즘은 n이 큰 값일 경우에 매우 비효율적이다. 따라서 가능하면 다른 접근 방법이나 최적화 기법을 고려해야 한다.&lt;/p&gt;</description>
      <category>Data Structure &amp;amp; Algorithm</category>
      <category>빅오</category>
      <category>시간복잡도</category>
      <category>알고리즘</category>
      <category>자료구조</category>
      <category>코딩테스트</category>
      <category>파이썬</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/201</guid>
      <comments>https://fromnowwon.tistory.com/entry/python-bigO#entry201comment</comments>
      <pubDate>Thu, 22 Jun 2023 13:36:20 +0900</pubDate>
    </item>
    <item>
      <title>HTTP 상태 코드 (status code)의 이해와 처리</title>
      <link>https://fromnowwon.tistory.com/entry/http-status-code</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;웹 상에서 &amp;ldquo;404 Not Found(찾을 수 없음)&amp;rdquo; 또는 &quot;500 Internal Server Error(내부 서버 오류)&quot;와 같은 오류 메시지가 표시된 적이 있을 것입니다. HTTP 상태 코드라고 하는 이러한 암호 코드는 웹에서 데이터 통신의 기반이 되는 하이퍼텍스트 전송 프로토콜(HTTP)의 필수 요소입니다. 이 글에서는 HTTP 상태 코드의 중요성, 대표적인 상태 코드 유형, 효과적인 처리 방법을 살펴보며 HTTP 상태 코드에 대해 자세히 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-3749995100298532&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;http-상태란&quot; data-ke-size=&quot;size26&quot;&gt;HTTP 상태란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 상태(status)란 웹 서버가 HTTP 요청에 대한 응답으로 웹 브라우저에 전송하는 3자리 숫자 코드를 말합니다. 이러한 상태 코드는 요청된 작업의 성공 또는 실패에 대한 중요한 정보를 전달합니다. 상태 코드는 서로 다른 클래스로 그룹화되며, 각 클래스는 고유한 상태 코드 범주를 나타냅니다. 이러한 클래스와 각각의 코드를 자세히 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;xx-정보-코드&quot; data-ke-size=&quot;size23&quot;&gt;1xx: 정보 코드&lt;/h3&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;100 Continue: 서버가 요청의 초기 부분을 수신했으며 클라이언트는 나머지 요청을 계속 진행해도 된다는 정보를 알려줍니다.&lt;/li&gt;
&lt;li&gt;101 Switching Protocols: 클라이언트의 upgrade 요청 헤더에 대한 서버의 응답으로, 프로토콜을 전환 중임을 알려줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;xx-성공-코드&quot; data-ke-size=&quot;size23&quot;&gt;2XX: 성공 코드&lt;/h3&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;200 OK: 요청이 성공했으며 서버가 요청된 리소스를 반환했음을 알려줍니다.&lt;/li&gt;
&lt;li&gt;201 Created: 요청이 완료되어 새 리소스가 생성되었음을 알려줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;xx-리디렉션-코드&quot; data-ke-size=&quot;size23&quot;&gt;3xx: 리디렉션 코드&lt;/h3&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;301 Moved Permanently: 요청된 리소스가 새 URL로 영구적으로 이동되었음을 알려줍니다.&lt;/li&gt;
&lt;li&gt;302 Found: 요청된 리소스가 일시적으로 다른 URL에 있음을 알려줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;xx-클라이언트-오류-코드&quot; data-ke-size=&quot;size23&quot;&gt;4xx: 클라이언트 오류 코드&lt;/h3&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;400 Bad Request: 잘못된 구문이나 매개변수 누락으로 인해 서버가 요청을 이해할 수 없는 상태를 말합니다.&lt;/li&gt;
&lt;li&gt;403 Forbidden: 서버가 요청을 이해했지만 클라이언트에 요청된 리소스에 액세스 하는 데 필요한 권한이 없음을 나타냅니다. 이 상태 코드는 적절한 인증 없이 제한된 콘텐츠나 보호된 디렉터리에 액세스 하려고 할 때 자주 발생합니다.&lt;/li&gt;
&lt;li&gt;404 Not Found: 요청된 리소스를 서버에서 찾을 수 없는 상태를 말합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;xx-서버-오류-코드&quot; data-ke-size=&quot;size23&quot;&gt;5xx: 서버 오류 코드&lt;/h3&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;500 Internal Server Error: 내부 서버 오류를 나타내는 일반적인 오류 메시지입니다.&lt;/li&gt;
&lt;li&gt;503 Service Unavailable: 유지보수 또는 과부하로 인해 서버가 일시적으로 요청을 처리할 수 없음을 알려줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;http-상태-코드의-표준화&quot; data-ke-size=&quot;size26&quot;&gt;HTTP 상태 코드의 표준화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 상태 코드는 HTTP/1.1 프로토콜에 표준화되어 정의되어 있습니다. 이러한 표준화는 웹 서버와 브라우저 간의 일관된 통신을 보장하여 다양한 시나리오와 오류를 적절히 처리할 수 있도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;리디렉션과-302-리디렉션의-차이점&quot; data-ke-size=&quot;size26&quot;&gt;301 리디렉션과 302 리디렉션의 차이점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;301 리디렉션은 요청된 리소스가 새로운 위치로 영구적으로 이동되었음을 클라이언트에게 알립니다. 검색 엔진은 일반적으로 301 리디렉션이 발생하면 이전 URL에서 새 URL로 순위와 색인을 전송합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 302 리디렉션은 요청된 리소스가 일시적으로 다른 URL에 있음을 나타냅니다. 301 리디렉션과 달리 검색 엔진은 일반적으로 302 리디렉션을 통해 순위와 색인을 새 URL로 이전하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;웹사이트에서-404-오류를-효과적으로-처리하는-방법&quot; data-ke-size=&quot;size26&quot;&gt;웹사이트에서 404 오류를 효과적으로 처리하는 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹사이트의 사용자 경험의 향상을 위해서 404 오류를 적절히 처리하는 것은 중요합니다. 다음은 404 오류를 효과적으로 처리하기 위한 몇 가지 방법입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에러 페이지를 사용자 정의합니다: 404 에러 페이지를 만들고, 사용자가 웹사이트의 관련 콘텐츠로 다시 이동할 수 있도록 안내하는 역할을 합니다.&lt;/li&gt;
&lt;li&gt;리디렉션 구현하기: 리소스가 영구적으로 새 위치로 이동한 경우 301 리디렉션을 사용하여 사용자와 검색 엔진을 새 URL로 리디렉션 합니다.&lt;/li&gt;
&lt;li&gt;끊어진 링크 수정: 웹사이트의 끊어진 링크를 정기적으로 모니터링하고 수정하여 404 오류 발생을 최소화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;내부-서버-오류를-해결-방법&quot; data-ke-size=&quot;size26&quot;&gt;500 내부 서버 오류를 해결 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;500 내부 서버 오류가 발생하면 몇 가지 단계를 통해 문제를 해결할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 로그를 확인합니다: 서버 로그를 검토하여 특정 오류 메시지나 오류 원인에 대한 단서를 파악합니다.&lt;/li&gt;
&lt;li&gt;플러그인 또는 확장 프로그램을 일시적으로 비활성화합니다: 서버와 충돌을 일으킬 수 있는 최근에 설치한 플러그인이나 확장 프로그램을 모두 비활성화하세요.&lt;/li&gt;
&lt;li&gt;문제가 지속되면 백엔드 개발자에 해당 오류를 해결해 달라고 요청합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 상태 코드는 웹 기능에 중요한 역할을 합니다. 웹사이트 소유자와 개발자는 이러한 코드를 이해하면 문제를 효과적으로 진단하고 해결하여 원활한 사용자 경험을 보장할 수 있습니다.&lt;/p&gt;</description>
      <category>Network</category>
      <category>HTTP</category>
      <category>Status</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/200</guid>
      <comments>https://fromnowwon.tistory.com/entry/http-status-code#entry200comment</comments>
      <pubDate>Wed, 31 May 2023 16:55:10 +0900</pubDate>
    </item>
    <item>
      <title>AJAX 대신 XMLHttpRequest 사용해서 파일 다운로드 기능 구현하기</title>
      <link>https://fromnowwon.tistory.com/entry/XMLHttpRequest</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;서버에 요청해 받은 파일로 파일 다운로드 기능을 구현해야 하는데, 회사에서 사용하고 있는 JQuery 버전이 낮아 JQuery AJAX로는 구현할 수 없었습니다. 때문에 JQuery AJAX 대신 XMLHttpRequest를 사용해 해결하였으며 이번 기회에 XMLHttpRequest에 대해 정리해보고자 합니다.&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;XMLHttpRequest란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XMLHttpRequest는 JavaScript에서 HTTP 요청을 보내는 JavaScript 객체입니다. 이 객체를 사용하여 서버와 통신하고, 서버로부터 데이터를 받아올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XMLHttpRequest를 사용하면 JavaScript를 사용하여 웹 페이지의 동적인 부분을 업데이트할 수 있습니다. 예를 들어, 사용자가 어떤 작업을 수행하면, XMLHttpRequest를 사용하여 서버와 통신하고, 데이터를 가져와서 페이지를 업데이트할 수 있습니다. 이 방법을 사용하면 페이지를 다시 로드하지 않아도 새로운 정보를 가져올 수 있습니다. 또한, XMLHttpRequest를 사용하여 파일을 다운로드하면, 다운로드 진행 상황을 추적하거나 중단하는 등의 기능을 추가할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 코드&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;var xhr = new XMLHttpRequest();
xhr.open('GET', '&amp;lt;http://example.com&amp;gt;', true);
xhr.onreadystatechange = function() {
  if (this.readyState === XMLHttpRequest.DONE &amp;amp;&amp;amp; this.status === 200) {
    console.log(this.responseText);
  }
};
xhr.send();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 &lt;code&gt;xhr.open()&lt;/code&gt; 메서드의 첫 번째 매개변수는 HTTP 메서드 (GET, POST 등)를, 두 번째 매개변수는 요청을 보낼 URL을, 세 번째 매개변수는 비동기 여부를 나타냅니다. &lt;code&gt;onreadystatechange&lt;/code&gt; 이벤트 핸들러에서는 요청의 상태가 &lt;code&gt;XMLHttpRequest.DONE&lt;/code&gt;이며 응답 상태 코드가 200일 때 &lt;code&gt;responseText&lt;/code&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;AJAX로 파일 다운로드 구현이 안 되는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AJAX는 브라우저 내부에서 동작하는 JavaScript를 사용하여 비동기적으로 서버와 통신하는 기술입니다. 이때, 브라우저의 보안 정책으로 인해 파일 다운로드 기능이 구현되지 않을 수 있습니다. 브라우저는 AJAX 요청에서 반환된 데이터를 보안상의 이유로 로컬 파일 시스템에 직접 접근할 수 없습니다. 따라서 AJAX를 사용하여 파일을 다운로드하려면, 위에서 설명한 XMLHttpRequest를 사용하는 방법으로 해결해야 합니다.&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;XMLHttpRequest로 파일 다운로드 기능 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XMLHttpRequest를 사용하여 파일을 다운로드하려면 &lt;code&gt;responseType&lt;/code&gt; 속성을 &lt;code&gt;&quot;blob&quot;&lt;/code&gt;으로 설정하고, &lt;code&gt;onload&lt;/code&gt; 이벤트 핸들러에서 &lt;code&gt;URL.createObjectURL()&lt;/code&gt;을 사용하여 Blob 객체의 URL을 생성해야 합니다. 아래는 파일 다운로드를 위한 예시 코드입니다.&lt;/p&gt;
&lt;pre class=&quot;qml&quot;&gt;&lt;code&gt;var xhr = new XMLHttpRequest();
var url = 'http://example.com/file.pdf';
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
  if (this.status === 200) {
    var blob = new Blob([this.response], { type: 'application/pdf' });
    var downloadUrl = URL.createObjectURL(blob);
    var a = document.createElement(&quot;a&quot;);
    a.href = downloadUrl;
    a.download = 'file.pdf';
    document.body.appendChild(a);
    a.click();
  }
};
xhr.send();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 &lt;code&gt;xhr.open()&lt;/code&gt; 메소드의 첫 번째 매개변수는 HTTP 메서드 (GET, POST 등)를, 두 번째 매개변수는 요청을 보낼 파일의 URL을, 세 번째 매개변수는 비동기 여부를 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;responseType&lt;/code&gt; 속성을 &lt;code&gt;&quot;blob&quot;&lt;/code&gt;으로 설정하여 Blob 객체로 데이터를 받아옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;onload&lt;/code&gt; 이벤트 핸들러에서 &lt;code&gt;Blob&lt;/code&gt; 객체를 생성하고, &lt;code&gt;URL.createObjectURL()&lt;/code&gt;을 사용하여 Blob 객체의 URL을 생성합니다. 그리고 생성된 URL로 &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 요소를 생성하여 &lt;code&gt;download&lt;/code&gt; 속성을 설정한 후, &lt;code&gt;click()&lt;/code&gt; 메소드를 호출하여 다운로드를 시작합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;blob&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blob은 바이너리 데이터의 불변성 버퍼입니다. 파일, 이미지, 오디오 또는 기타 바이너리 데이터를 나타낼 수 있습니다. 이러한 데이터를 Blob 객체로 만들면, URL.createObjectURL()을 사용하여 해당 Blob 객체의 URL을 생성할 수 있습니다. 이 URL은 이미지 태그의 src 속성 또는 다운로드 링크의 href 속성 등에서 사용할 수 있습니다.&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;XMLHttpRequest 지원 중단?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XMLHttpRequest는 최신 브라우저에서는 더 이상 권장되지 않는 기술이지만, 이전 버전과의 호환성을 위해 계속해서 지원될 예정입니다. 사실 Fetch API가 더 최신이며 더 권장되는 방법이므로, 가능하면 Fetch API를 사용하는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실무에서 사용하는 JavaScript나 JQuery 버전이 낮다면 XMLHttpRequest를 불가피하게 사용해야 할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;XMLHttpRequest VS. Fetch API&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XMLHttpRequest는 비동기적으로 서버와 통신하는 JavaScript 객체입니다. 반면에 Fetch API는 Promise 기반으로 비동기적으로 서버와 통신합니다.&lt;/li&gt;
&lt;li&gt;XMLHttpRequest는 요청과 응답을 다루는 방법이 불편합니다. 반면에 Fetch API는 간결하고 편리하게 요청과 응답을 다룰 수 있습니다.&lt;/li&gt;
&lt;li&gt;XMLHttpRequest는 크로스 도메인 요청에 대한 보안 정책을 우회하기 위해 CORS를 사용해야 합니다. Fetch API는 기본적으로 CORS를 지원합니다.&lt;/li&gt;
&lt;li&gt;XMLHttpRequest는 업로드와 다운로드 진행 상황을 추적하기 위해 복잡한 코드가 필요합니다. 반면에 Fetch API는 진행 상황을 추적하는 기능을 제공하지 않습니다.&lt;/li&gt;
&lt;li&gt;XMLHttpRequest는 오래된 기술이므로, Fetch API가 더 최신이며 더욱 권장되는 방법입니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>JavaScript</category>
      <category>XMLHttpRequest</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/199</guid>
      <comments>https://fromnowwon.tistory.com/entry/XMLHttpRequest#entry199comment</comments>
      <pubDate>Fri, 31 Mar 2023 09:41:18 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] EC2 요금 모델(pricing model) 정리</title>
      <link>https://fromnowwon.tistory.com/entry/aws-ec2-pricing-model</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. On-demand(온디멘드)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용한 인스턴스에 대해 사용한 만큼 시간당 요금을 지불한다. 애플리케이션 수요에 따라 컴퓨터 용량(compute capacity)을 늘이거나 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;On-demand가 적합한 경우&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선결제 금액(No upfront payments)이나 장기 약정(No long-term commitments) 없이&amp;nbsp;저렴하고 유연하게 Amazon EC2를 사용하기를 원하는 사용자&lt;/li&gt;
&lt;li&gt;단기의 갑작스럽고 예측할 수 없는 워크로드가 있으면서 중단되어서는 안 되는 애플리케이션&lt;/li&gt;
&lt;li&gt;Amazon EC2로 처음 개발하거나 테스트 중인 애플리케이션&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Spot instance(스팟 인스턴스)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 90% 저렴한 가격으로 EC2 예비 용량을 사용할 수 있다. (&lt;b&gt;spare&lt;/b&gt; Amazon EC2 computing capacity)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You pay the Spot price that's in effect for the time period your instances are running.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(인스턴스가 실행되는 동안 유효한 가격 지불)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spot instance prices are set by Amazon EC2 and adjust gradually &lt;b&gt;based on long-term trends in supply and demand&lt;/b&gt; for Spot Instance capacity.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(스팟 인스턴스 가격은 EC2에서 설정하며 스팟 인스턴스 용량에 대한 &lt;b&gt;수요와 공급의 장기적인 추세에 따라 점진적으로 조정&lt;/b&gt;된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Spot instance가 적합한 경우&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Saving plans(절감형 플랜, 예약 인스턴스)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1년 또는 3년 동안 일정 사용량 약정(시간당 요금 기준으로 측정)을 조건으로 저렴한 요금을 제공하는 유연한 모델이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Saving plans가 적합한 경우&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;비용을 절약하기 위해 1년 또는 3년 약정할 수 있는 사용자&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Dedicated Hosts(전용 호스팅)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물리적인 EC2 서버를 전용으로 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Window server, SQL server, SUSE Linux Enterprise server 등 기존 서버 한정 소프트웨어 라이선스를 사용할 수 있으므로 비용을 절감할 뿐만 아니라 규정 준수 요구 사항도 충족할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;온디맨드로 구매 가능하다 (시간당)&lt;/li&gt;
&lt;li&gt;온디맨드에 비해 70% 저렴한 예약 인스턴스로 구매 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AWS</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/198</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-ec2-pricing-model#entry198comment</comments>
      <pubDate>Tue, 7 Mar 2023 21:23:12 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Amazon EC2 스팟(Spot) instance</title>
      <link>https://fromnowwon.tistory.com/entry/aws-spot-instance</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;스팟 인스턴스란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전 약정 없이 On-demand보다 최대 90% 절감된 비용으로 미사용 컴퓨팅 용량을 사용할 수 있는 인스턴스이다. 사용하려는 인스턴스의 현재 시간 금액만 지불하면 된다. 스팟 인스턴스를 On-demand, RI, Savings Plans 인스턴스와 손쉽게 결합하여 비용을 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스팟 인스턴트의 장점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 저렴하고 예측 가능한 요금&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 대규모&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 저렴한 비용으로 대규모 워크로드를 실행하거나, 병렬 작업을 통해 작업을 가속화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 사용 편의성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AWS</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/197</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-spot-instance#entry197comment</comments>
      <pubDate>Sun, 5 Mar 2023 16:49:12 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] SSO(Single Sign-On)란?</title>
      <link>https://fromnowwon.tistory.com/entry/aws-sso</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;SSO(Single Sign-ON)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSO는 이름에서 알 수 있듯이 1회 사용자 인증을 통해 AWS 다수의 서비스에 대한 사용자 로그인을 허용하는 인증 솔루션이다. 반복되는 로그인 없이 모든 보호 리소스에 접근할 수 있어 보안은 물론이고 사용자 경험까지 모두 충족할 수 있다.&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;SSO 이점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 암호 보안 강화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 생산성 향상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 비용 절감&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 보안 태세 개선&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 보다 나은 고객 경험 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AWS</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/196</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-sso#entry196comment</comments>
      <pubDate>Sun, 5 Mar 2023 16:16:12 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] 서버리스(Serverless) 서비스 플랫폼</title>
      <link>https://fromnowwon.tistory.com/entry/aws-serverless</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서버리스란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버리스 환경에서는 서버를 고려하지 않아도 애플리케이션 서비스를 구축하고 실행할 수 있다. 여러 프로비저닝 같은 인프라 관리 작업을 생략할 수 있다. &lt;span&gt;AWS에서 서버를 관리해 주기 때문에 건드릴 일이 없다. (완전관리형)&lt;span&gt; &lt;/span&gt;&lt;/span&gt;거의 모든 유형의 애플리케이션 및 백엔드 서비스를 서버리스로 구축할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서버리스 사용 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 서버를 관리할 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 확장이 유연하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 서버 단위가 아닌 처리량 또는 실행 기간만큼 요금을 지불한다. (종량제)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 자동화된 고가용성과 내결함성을 갖추고 있다.&lt;/p&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;AWS 서버리스 서비스&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 184px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;카테고리&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;서비스&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;컴퓨팅&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: left;&quot;&gt;AWS Lambda&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: left;&quot;&gt;AWS Lambda를 사용하면 함수 계층에서 마이크로서비스 아키텍처, 배포 및 실행 관리를 지원하는 관리형 플랫폼에서 서버리스 애플리케이션을 실행할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;API 프록시&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: left;&quot;&gt;API Gateway&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: left;&quot;&gt;Amazon API Gateway는 어떤 규모에서든 개발자가 API를 손쉽게 생성, 게시, 유지 간리, 모니터링 및 보호할 수 있도록 하는 완전관리형 서비스이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 51px; text-align: center;&quot; rowspan=&quot;3&quot;&gt;메시징 및 통합&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;SNS&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;Amazon SNS는 마이크로서비스, 분산 시스템 및 서버리스 애플리케이션을 쉽게 분리하고 확장할 수 있기 해주는 완전관리형 게시/구독 메시징 서비스이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;SQS&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;Amazon SQS는 마이크로서비스, 분산 시스템 및 서버리스 애플리케이션을 쉽게 분리하고 확장할 수 있게 지원하는 완전관리형 메시지 대기열 서비스이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;EventBridge&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: left;&quot;&gt;Amazon EventBridge는 자체 애플리케이션, 통합된 Software-as-Service(SaaS) 애플리케이션 및 AWS 서비스의 데이터를 사용하여 애플리케이션을 쉽게 연결할 수 있게 지원하는 서버리스 이벤트 버스이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;오케스트레이션&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: left;&quot;&gt;Step Functions&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: left;&quot;&gt;AWS Step Functions를 사용하면 시각적 워크플로를 통해 배포된 애플리케이션의 구성 요소를 손쉽게 조정할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 57px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 57px; text-align: center;&quot;&gt;데이터베이스&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 57px; text-align: left;&quot;&gt;DynamoDB&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 57px; text-align: left;&quot;&gt;DynamoDB는 용량을 조정하고 성능을 유지하기 위해 자동으로 확장 및 축소되는 서버리스 서비스이다.&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;/div&gt;</description>
      <category>AWS</category>
      <category>AWS</category>
      <category>serverless</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/195</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-serverless#entry195comment</comments>
      <pubDate>Fri, 3 Mar 2023 21:46:09 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] CAPEX(설비투자비용) VS. OPEX(운영비용)</title>
      <link>https://fromnowwon.tistory.com/entry/capex-opex-cloud</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;on-premises(자체 보유) 데이터 센터를 AWS Cloud로 이동하게 되면 비용적으로 어떤 이점이 있는지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CAPEX(upfront capital expense)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CAPEX는 설비 투자 비용으로, 초반에 자체 데이터 센터를 갖추기 위한 초기 비용을 말한다. (데이터 센터 혹은 물리적 서버)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;OPEX(variable operational expense)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OPEX는 데이터 센터를 갖춘 후 운영 비용을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드는 비싼 초기 자본의 투자를 가변 운영 비용으로 전환하도록 도와준다. 물리적 데이터센터 설치가 필요 없고, 사용한 만큼만 지불하면 되기 때문이다. 이렇게 간편한 지불 방식은 서비스 구성에 더 집중할 수 있게 해 준다.&lt;/p&gt;
  &lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
  &lt;/div&gt;</description>
      <category>AWS</category>
      <category>AWS</category>
      <category>CAPEX</category>
      <category>cloud</category>
      <category>OPEX</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/194</guid>
      <comments>https://fromnowwon.tistory.com/entry/capex-opex-cloud#entry194comment</comments>
      <pubDate>Wed, 1 Mar 2023 20:51:40 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Organizations란</title>
      <link>https://fromnowwon.tistory.com/entry/aws-organizations</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AWS Organization이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Organization은 생성한 여러 계정들을 조직으로 통합하고 중앙 집중식으로 관리할 수 있도록 하는 서비스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주요 기능과 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 AWS 계정 중앙 집중식 관리&lt;/li&gt;
&lt;li&gt;모든 계정에 대해 통합 결제&lt;/li&gt;
&lt;li&gt;계정의 계층적 조직 단위로 그룹화(OU)&lt;/li&gt;
&lt;li&gt;각 계정의 액세스 및 API를 중앙에서 통합적 관리&lt;/li&gt;
&lt;li&gt;리소스 태그 표준화&lt;/li&gt;
&lt;li&gt;다른 AWS 서비스와 통합&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;/div&gt;</description>
      <category>AWS</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/193</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-organizations#entry193comment</comments>
      <pubDate>Sat, 25 Feb 2023 14:40:54 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Concierge / CloudFormation / Manage Console</title>
      <link>https://fromnowwon.tistory.com/entry/aws-concierge-cloudFormation-manage-console</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AWS Concierge&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숙련된 클라우드 기술 담당자를 배치하여 호텔 컨시어지와 같은 고객 밀착형, 맞춤형 서비스 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AWS CloudFormation&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인프라 간소화해주는 서비스로 템플릿 파일만 작성하면 AWS 서비스를 알아서 구성해줌. (As Code)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AWS Manage Console&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드를 액세스하고 관리하는 데 필요한 모든 것을 하나의 웹 인터페이스로 관리&lt;/p&gt;
  &lt;/div&gt;</description>
      <category>AWS</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/192</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-concierge-cloudFormation-manage-console#entry192comment</comments>
      <pubDate>Sat, 25 Feb 2023 14:09:20 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] CloudFormation이란</title>
      <link>https://fromnowwon.tistory.com/entry/cloudFormation</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CloudFormation이란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CloudFormation 간단한 텍스트 파일을 사용해서 클라우드 환경의 모든 인프라 리소스를 프로비저닝 할 수 있게 해주는 서비스다. 자동화된 방식을 통해 모든 리전 및 계정의 애플리케이션에 필요한 리소스를 모델링하고 프로비저닝 하여, 실행되는 애플리케이션에만 집중할 수 있도록 도와준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 리소스를 개별적으로 생성하고 구성할 필요가 없다. CloudFormation에서 모두 처리해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;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;/div&gt;</description>
      <category>AWS</category>
      <category>AWS</category>
      <category>CloudFormation</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/191</guid>
      <comments>https://fromnowwon.tistory.com/entry/cloudFormation#entry191comment</comments>
      <pubDate>Thu, 23 Feb 2023 21:27:54 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] S3, EBS, EFS 비교</title>
      <link>https://fromnowwon.tistory.com/entry/s3-ebs-efs</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3, EBS, EFS 모두 &lt;span&gt;Amazon에서 제공하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;파일 저장 공간 서비스이다. 각 서비스를 특징 별로 구분하여 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Keyword&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;S3&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 단위 스토리지 / 저렴한 비용 / 어디서나 접근 가능&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;EBS&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블록 단위 스토리지 / 가장 빠름 / 단일 인스턴스에만 부착 가능&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;EFS&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 기반 스토리지 / 네트워크를 통한 파일 데이터 공유 / 여러 인스턴스에서 접근 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;S3 / EBS / EFS 비교표&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 202px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;b&gt;Amazon S3&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;b&gt;Amazon EBS&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;b&gt;Amazon EFS&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;b&gt;스토리지 유형&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;Object Storage&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;Block Level Storage&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;Shared File Storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;b&gt;Latency (지연/대기 시간)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;낮음&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;가장 낮고 일관됨&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;낮고 일관됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;b&gt;Read/Write 속도&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Read는 빠르지만 Write는 느림&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Read/Write 매우 빠름&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #373e48;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Read/Write 빠름&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 40px;&quot;&gt;&lt;b&gt;데이터 수정&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 40px;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;수정 불가&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;덮어쓰기로 처리&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 40px;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;수정 가능&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 40px;&quot;&gt;수정 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;b&gt;비용&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;비교적 저렴&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;평균&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;비교적 비쌈&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;b&gt;가용성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;여러 AZ에 중복 저장&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;단일 AZ에 중복 저장&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;여러 AZ에 중복 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;b&gt;액세스&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;웹을 통해 어디서나 접근 가능&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;하나의 AZ에 속한 하나의 인스턴스에서만 접근 가능&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;하나~수천 개의 여러 인스턴스에서 접근 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;b&gt;EC2에 마운트&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;불가&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;가능&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;b&gt;호환성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;낮음&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;높음&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;b&gt;사용 환경&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- Write once Read many times&lt;br /&gt;- 빈번한 업데이트가 요구되지 않는 환경&lt;br /&gt;- 정적 웹사이트 호스팅 지원&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 빈번한 Read/Write 환경&lt;br /&gt;- 단일 인스턴스에 고성능 스토리지 서비스가 필요한 경우&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;- 빈번한 Read/Write&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;환경&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;상세 설명&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Amazon S3 (Simple Storage Service)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상 용량 제한 없음 (파일 사이즈 고려하지 않아도 됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 웹 호스팅을 위한 파일이나 로그 파일 등 빈번한 업데이트가 없는 파일을 저렴하게 관리하고 싶을 때 용이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS나 DB처럼 빠르고 빈번한 R/W 작업이 요구되는 환경에는 적합하지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러가 많고, 파일 Sync가 맞지 않는 경우도 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Amazon&lt;span&gt;&amp;nbsp;&lt;/span&gt;EBS (Elastic Block Storage)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2에서 사용하도록 설계된 사용하기 쉬운 고성능 블록 스트리지 서비스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2에 기본적으로 붙어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3나 EFS와 달리 독립형 스토리지가 아니라 EC2와 함께 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스에는 볼륨을 여러 개 연결할 수 있지만, 볼륨에는 하나의 인스턴스만 연결 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 인스턴스에 사용할 영구 데이터를 저장할 때 사용 (물리적 디스크 드라이브와 유사한 역할)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빠른 Read/Write 속도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EBS 생성 시, 특정 AZ에 배치되며 그곳에서 자동으로 복제된다. (단일 AZ에 중복 저장)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로비저닝 된 크기의 볼륨에 데이터를 저장하며, 한 번 늘어난 볼륨을 다시 줄일 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Amazon&lt;span&gt;&amp;nbsp;&lt;/span&gt;EFS (Elastic File System)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 서비스, On-Premise 리소스에서 사용할 수 있는 간단하고 확장 가능한 완전 관리형 NFS 파일 시스템&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상 용량 제한 없음 (파일 사이즈 고려하지 않아도 됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 서버에서 하나의 파일 시스템으로 데이터를 공유하고 싶을 때 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 인스턴스가 EFS에 동시 액세스할 수 있음 (공유 가능)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 AZ에 복제되어 EBS보다 더 높은 가용성 자랑 (어느 AZ든 접근하여 마운트 가능)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Site-to-Site VPN 혹은 DX와 연결되어 있으면 On-Premise와 연결 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VPC 내 EC2 인스턴스는 직접 액세스 할 수 있다.&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;Block Level Storage VS. Object Storage&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Block Level Storage&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 블록으로 나뉘어 있는 형태의 스토리지. 파일을 수정하면 해당 블록 몇 개만 일부 변경된다. 모든 블록을 업데이트하지 않아도 된다는 말이다. 때문에 Block Level Storage는 빠른 속도를 자랑한다. Read/Write가 빈번한 환경에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Object Storage&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일이 수정되면 새로운 Object로 인식하여 기존 파일은 지워지고 새로운 파일로 대체된다. 따라서 데이터를 수정하는 경우 비교적 시간이 오래 걸린다. Read/Write가 빈번하지 않은 환경에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>AWS</category>
      <category>AWS</category>
      <category>Block Level Storage</category>
      <category>Object Storage</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/190</guid>
      <comments>https://fromnowwon.tistory.com/entry/s3-ebs-efs#entry190comment</comments>
      <pubDate>Thu, 23 Feb 2023 11:20:04 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript] 느낌표 두 개 (!!) 논리 부정 연산자</title>
      <link>https://fromnowwon.tistory.com/entry/double-not</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단일 느낌표(!) - Logical NOT&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 느낌표 연산자는 논리 부정(Not) 연산자라고 한다. 오른쪽에 붙은 피연산자의 값을 역전시켜 boolean 타입으로 반환한다. 실무에서는 조건문에서 많이 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1677109411776&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (!Array.length) console.log(&quot;빈 배열&quot;);

if (!data) console.log(&quot;데이터 없음&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이중 느낌표(!!) - Double NOT&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중 느낌표는 단일 느낌표와 같이 피연산자를 boolean 타입으로 값을 반환한다. 오른쪽에 붙은 피연산자가 true/false로 확실하게 정해지지 않은 경우 확실한 true/false 값을 가지도록 하는 게 목적이다. true/false 성격만 가지고 있던 값을 명확하게 true/false로 반환해 준다. (&lt;span&gt;truthy/falsy&amp;nbsp; -&amp;gt; true/false)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 boolean 타입이 아닌 값들도 true/false 성격을 가지고 있다. if 조건문에서 확인해 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1677111231323&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (true) { /* 실행 */ }
if (false) { /* 실행되지 않음 */ }
if (1) { /* 실행 */ }
if (0) { /* 실행되지 않음 */ }
if (-1) { /* 실행 */ }
if (&quot;true&quot;) { /* 실행 */ }
if (&quot;false&quot;) { /* 실행 */ }
if (&quot;1&quot;) { /* 실행 */ }
if (&quot;0&quot;) { /* 실행 */ }
if (&quot;-1&quot;) { /* 실행 */ }
if (&quot;&quot;) { /* 실행되지 않음 */ }
if (null) { /* 실행되지 않음 */ }
if (undefined) { /* 실행되지 않음 */ }
if ([]) { /* 실행 */ }
if ({}) { /* 실행 */ }
if ([[]]) { /* 실행 */ }
if ([0]) { /* 실행 */ }
if ([1]) { /* 실행 */ }
if (NaN) { /* 실행되지 않음 */ }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이중 느낌표 연산자의 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드는 리액트에서 input을 사용할 때 삼항 연산자를 통해 disabled의 true와 false를 정하는 경우이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1677030863764&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input disabled={(email === '' || status === 'REMOVE') ? true : false} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 아래와 같이 변환할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1677030874332&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input disabled={!!(email === '' || status === 'REMOVE')} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;email이 빈 값이거나 status가 'REMOVE'일 때에는 무조건 true를 반환하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT#double_not_!!&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT#double_not_!!&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dorey.github.io/JavaScript-Equality-Table/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dorey.github.io/JavaScript-Equality-Table/&lt;/a&gt;&lt;/p&gt;</description>
      <category>JavaScript</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/189</guid>
      <comments>https://fromnowwon.tistory.com/entry/double-not#entry189comment</comments>
      <pubDate>Thu, 23 Feb 2023 09:26:52 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Trusted Advisor란? 검사(평가) 카테고리</title>
      <link>https://fromnowwon.tistory.com/entry/aws-trusted-advisor</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Trusted Advisor&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Trusted Advisor는 AWS 인프라에 대해 검사 및 평가를 통해 기존 모범 사례들을 달성할 수 있도록 권장 사항들을 제시한다. 이를 통해 인프라를 최적화하여 비용 절감, 보안 및 성능 개선 등에 도움을 줄 수 있다.&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;Trusted Advisor 검사(평가) 카테고리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Cost optimization (비용 최적화)&lt;/b&gt; - 유료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Performance (성능)&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 유료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.&amp;nbsp;Fault tolerance (내결함성, 장애 내구성)&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 유료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Service limits (서비스 할당량)&lt;/b&gt; - 무료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;5.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Security (보안)&lt;/b&gt; - 부분적 무료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>AWS</category>
      <category>Trusted Advisor</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/188</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-trusted-advisor#entry188comment</comments>
      <pubDate>Mon, 20 Feb 2023 21:27:05 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Lambda란? Serverless 컴퓨팅 인프라 구축</title>
      <link>https://fromnowwon.tistory.com/entry/aws-lambda</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;컴퓨팅 인프라 구축 방법의 발전&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터센터 &amp;gt; IaaS/PaaS &amp;gt; 컨테이너 &amp;gt; Serverless&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;Serverless&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;사용한 만큼만 비용을 지불한다. (on-demand)&lt;/li&gt;
&lt;li&gt;고가용성과 장애 내구성이 확보되어 있다.&lt;/li&gt;
&lt;li&gt;빠르게 배포하고 업데이트 가능&lt;/li&gt;
&lt;li&gt;Serverless 환경을 잘 활용할 수 있는 아키텍처 필요
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AWS Lambda&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Lambda is a compute service that lets you run code without provisioning or managing servers.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lambda runs your code only when needed and scales automatically, from a few requests per day to thousands per second.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;You pay only for the compute time that you consume&lt;/b&gt; - there is no charge when your code is not running.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;With Lambda, you can run code for virtually any type of application or backend service, all with zero administration.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lambda runs your code on &lt;b&gt;a high-availability compute infrastructure&lt;/b&gt; and performs all of the administration of the compute infrastructure and performs all of the administration of the compute resources, including server and operating system maintenance, capacity provisioning and automatic scaling, code monitoring and logging.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS의 Serverless 컴퓨팅 서비스
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;코드와 코드를 실행하기 위한 파일들을 업로드하면 서버 프로비전 없이 코드 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다양한 AWS 서비스에서 Lambda를 활용&lt;/li&gt;
&lt;li&gt;다양한 언어 지원
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Java, C#, Go, Node.js, Python, Ruby, .NET(#C/PowerShell)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lambda는 크게 두 가지 방법으로 호출
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Event 기반&lt;/li&gt;
&lt;li&gt;AWS의 다른 서비스 혹은 애플리케이션에서 직접 혹은 API Gateway를 통해서 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;저렴한 가격
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;처음 100만 건 호출 무료, 이후 100만 건 당 $0.2 (메모리/컴퓨팅 사용에 따라 차이)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/-BEou7aN7AY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://youtu.be/-BEou7aN7AY&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>AWS</category>
      <category>AWS</category>
      <category>lambda</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/187</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-lambda#entry187comment</comments>
      <pubDate>Mon, 20 Feb 2023 09:24:41 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] 온프레미스를 클라우드에 연결하는 방법 2가지</title>
      <link>https://fromnowwon.tistory.com/entry/aws-vpn-vpc-on-premises</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Over internet using VPN connection&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- VPN을 사용해서 인터넷으로 연결&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AWS Virtual Private Network(VPN) solutions establish secure connections via the public internet between your on-premises networks, remote offices, client devices, and the AWS global network.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Amazon Virtual Private Computer(VPC)는 가상 네트워크 센터로, 온프레미스와 연결하기 위해서는 AWS VPN이 필요하다.&lt;/p&gt;
&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;2. Over physical fiber cable using DirectConnect&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 케이블 선으로 직접 연결&lt;/p&gt;
  &lt;/div&gt;</description>
      <category>AWS</category>
      <category>VPC</category>
      <category>vpn</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/186</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-vpn-vpc-on-premises#entry186comment</comments>
      <pubDate>Sun, 19 Feb 2023 21:50:30 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] 클라우드 컴퓨팅 장점 6가지</title>
      <link>https://fromnowwon.tistory.com/entry/aws-cloud-computing-adventages</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6 Adventages of Cloud Computing&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Trade capital expense for variable expense&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 자본 비용을 변동 비용으로 대체할 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용한 양에 대해서만 변동적으로 지불하기 때문에 초기 자본 비용을 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Benefit from massive economies of scale&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 엄청난 규모의 경제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 소유하고 있는 인프라에서만 작업할 때보다 규모를 늘리기 쉬우며, 더 높은 규모의 경제를 달성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 결과적으로 사용한 만큼 지불하는 비용(*pay-as-you-go)이 줄어드는 효과가 발생한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;*pay-as-you-to: 약정 없이 사용한 만큼 과금&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Stop guessing about capacity (i.e. elasticity)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 용량 추정이 불필요해짐 (예: 탄력성)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 필요에 따라 용량을 확장하고 축소할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Increased speed and agility&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 속도와 민첩성 향상&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 클릭 몇 번만으로 데이터의 읽기/쓰기 작업이 가능하기 때문에 작업 시간이 단축되며, 조직의 민첩성이 향상된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. Stop spending money running and maintaining data centres&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 데이터 센터 운영 및 유지 관리 비용 지출 중단&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 클라우드 컴퓨팅을 사용하면 직접 데이터 센터를 운영할 필요가 없기 때문에 관련 비용 지출이 줄어든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 고객에 더 집중할 수 있는 시간을 확보할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. Go global in minutes&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 몇 분 만에 전 세계 배포 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 클릭 몇 번으로 전 세계 리전에 빠른 배포 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
  &lt;/div&gt;</description>
      <category>AWS</category>
      <category>AWS</category>
      <category>Cloud Computing</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/185</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-cloud-computing-adventages#entry185comment</comments>
      <pubDate>Sun, 19 Feb 2023 18:51:41 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] IAM User's Access key의 사용</title>
      <link>https://fromnowwon.tistory.com/entry/aws-iam-access-key</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AWS IAM (Identity and Access Management)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS IAM은 AWS 리소스에 대한 접근 권한을 관리할 수 있게 해주는 서비스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AWS IAM - Access key&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access key는 &lt;b&gt;IAM User&lt;/b&gt; 및 &lt;b&gt;AWS 루트 계정 User&lt;/b&gt;가 사용하는 보안 인증키다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장기적으로 자격을 증명할 수 있다. (long-term credentials)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access key는 &lt;b&gt;Access key ID&lt;/b&gt;와 &lt;b&gt;Secret Access key&lt;/b&gt;로 구성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access key를 통해 다음 두 가지 프로그래밍 요청에 서명할 수 있다. (access keys to sign programmatic requests)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CLI 요청 (직접적으로)&lt;/li&gt;
&lt;li&gt;AWS API 요청 (SDK API를 사용해서)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>AWS</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/184</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-iam-access-key#entry184comment</comments>
      <pubDate>Sun, 19 Feb 2023 17:52:08 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] AWS 서비스와 상호작용 하는 세 가지 방법</title>
      <link>https://fromnowwon.tistory.com/entry/aws-service-access</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 서비스에 접근하는 방법은 세 가지이다. 자주 나오는 지문이니 암기해 둘 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;There are three ways to interact with AWS Services.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. AWS Management Console&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Graphical interface to access AWS feathures&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Command Line Interface (CLI)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Lets you control AWS services from command line&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Software Development Kits (SDK)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Enable you to access AWS using a variety of popular programming languages.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>AWS</category>
      <category>AWS</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/183</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-service-access#entry183comment</comments>
      <pubDate>Sun, 19 Feb 2023 17:11:05 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] 데이터의 읽기/쓰기 속도에 따른 스토리지 서비스 분류</title>
      <link>https://fromnowwon.tistory.com/entry/aws-storage-read-write</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 신속한 데이터의 읽기/쓰기가 가능한 스토리지&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- Lower read/write latencies (낮은 읽기/쓰기 지연시간)&lt;br /&gt;- Read/write of constantly changing data (지속적으로 변화하는 데이터의 읽기/쓰기)&lt;br /&gt;- Must be updated very frequently (신속한 업데이트가 필요한 데이터)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. Amazon RDS (Relational Database Service)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- RDS is managed service for relational databases like MySQL and MariaDB&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Simple and fast to setup and scale&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Amazon EBS (Elastic Block Storage)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용하기 쉬운 대규모 고성능 스토리지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 고성능 워크로드에 맞춰 빠르게 확장 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Amazon EFS (Elastic File System)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AWS 컴퓨팅 시스템을 위한 공유 파일 시스템을 간편하고 빠르게 생성하고 구성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스토리지 및 성능이 완전 탄력적이므로 용량 계획이 필요 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Amazon DynamoDB&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모든 규모에서 빠르고 유연한 NoSQL 데이터베이스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 일관된 10밀리 초 미만의 성능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-5.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Relational databases running on Amazon EC2&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AWS RDS를 사용하면 번거로운 수동 작업을 처리할 필요가 없어 애플리케이션과 사용자에 집중이 가능 (완전 관리형 데이터베이스)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Amazon EC2를 통한 Amazon RDS를 데이터베이스 배포 단계에서 기본적으로 선택하는 것을 추천&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Amazon RDS를 사용하면 인스턴스에 문제가 발생했을 시 조치를 취할 수 있는 동기식 보조 인스턴스를 통해 가용성을 높일 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 읽기 전용 복제본을 사용하여 읽기 조정을 높일 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 빠르지는 않지만, 다른 성격의 스토리지&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. Amazon Glacier&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 비교적 저렴한 가격&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 읽기/쓰기 수시간 소요될 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터의 변화가 적은 장기 보관용 스토리지로 적합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. AWS Snowball&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 물리적인 디바이스를 사용해 대용량 데이터 관리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. Amazon Redshift&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 빅데이터 웨어하우스&lt;/p&gt;
&lt;/div&gt;</description>
      <category>AWS</category>
      <category>AWS</category>
      <category>스토리지</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/182</guid>
      <comments>https://fromnowwon.tistory.com/entry/aws-storage-read-write#entry182comment</comments>
      <pubDate>Fri, 17 Feb 2023 21:12:56 +0900</pubDate>
    </item>
    <item>
      <title>Postman에 Swagger API 연동(import) 하는 방법</title>
      <link>https://fromnowwon.tistory.com/entry/postman-swagger</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger에서 API 정보가 담긴 JSON 경로를 찾는다. 보통 Base URL 아래에 위치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;swagger-api-postman-import-01.jpg&quot; data-origin-width=&quot;1894&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7mTac/btrQPkmJD67/u4KPPqPioiTaykDyZHVujk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7mTac/btrQPkmJD67/u4KPPqPioiTaykDyZHVujk/img.jpg&quot; data-alt=&quot;swagger rest api&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7mTac/btrQPkmJD67/u4KPPqPioiTaykDyZHVujk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7mTac%2FbtrQPkmJD67%2Fu4KPPqPioiTaykDyZHVujk%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;1894&quot; height=&quot;523&quot; data-filename=&quot;swagger-api-postman-import-01.jpg&quot; data-origin-width=&quot;1894&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;swagger rest api&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import 방법은 여러 가지가 있다. 파일을 사용하거나 Raw text를 사용하거나 Link를 그대로 사용해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3749995100298532&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이 광고 - 상단 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-3749995100298532&quot; data-ad-slot=&quot;5363632735&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&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;nav class=&quot;index&quot;&gt;
&lt;h2 class=&quot;tit2&quot; data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;div class=&quot;wrap&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#cont1&quot;&gt;&lt;span class=&quot;txt&quot;&gt;Link import 방법&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#cont2&quot;&gt;&lt;span class=&quot;txt&quot;&gt;File Import 방법&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#cont3&quot;&gt;&lt;span class=&quot;txt&quot;&gt;Raw text Import 방법&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/nav&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;Postman - Swagger API import 방법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Link import 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌측 상단 import 클릭&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;swagger-api-import-postman.png&quot; data-origin-width=&quot;385&quot; data-origin-height=&quot;91&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2cajc/btrRmVmOS68/TnxEUN5bjzyEzw8or9BlI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2cajc/btrRmVmOS68/TnxEUN5bjzyEzw8or9BlI0/img.png&quot; data-alt=&quot;postman import&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2cajc/btrRmVmOS68/TnxEUN5bjzyEzw8or9BlI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2cajc%2FbtrRmVmOS68%2FTnxEUN5bjzyEzw8or9BlI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;385&quot; height=&quot;91&quot; data-filename=&quot;swagger-api-import-postman.png&quot; data-origin-width=&quot;385&quot; data-origin-height=&quot;91&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;postman import&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Link 탭에서 import 할 링크를 적고 Continue 버튼을 클릭한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;swagger-api-postman-import-03.jpg&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UPeqq/btrQPjH6xW4/0KRXao751esdoni0wnkKKk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UPeqq/btrQPjH6xW4/0KRXao751esdoni0wnkKKk/img.jpg&quot; data-alt=&quot;postman - import link&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UPeqq/btrQPjH6xW4/0KRXao751esdoni0wnkKKk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUPeqq%2FbtrQPjH6xW4%2F0KRXao751esdoni0wnkKKk%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;943&quot; height=&quot;720&quot; data-filename=&quot;swagger-api-postman-import-03.jpg&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;postman - import link&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collections에 세팅하고 싶다면 아래와 같이 Settings를 열고 Copy collections to workspace의 옵션을 켜주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;swagger-postman.jpg&quot; data-origin-width=&quot;1073&quot; data-origin-height=&quot;1055&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUh9Nw/btrQYGQKBac/1kj25pKxCKxdFbAFM5nu4K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUh9Nw/btrQYGQKBac/1kj25pKxCKxdFbAFM5nu4K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUh9Nw/btrQYGQKBac/1kj25pKxCKxdFbAFM5nu4K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUh9Nw%2FbtrQYGQKBac%2F1kj25pKxCKxdFbAFM5nu4K%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;1073&quot; height=&quot;1055&quot; data-filename=&quot;swagger-postman.jpg&quot; data-origin-width=&quot;1073&quot; data-origin-height=&quot;1055&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. File Import 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Swagger의 JSON 링크 경로를 들어가서 Ctrl+s 하면 JSON 파일을 저장할 수 있다. 이 파일을 사용하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;File 탭에서 해당 파일을 불러오면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;swagger-api-postman-import-04.jpg&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blqqP9/btrQOO2Ia75/XwOCnYFtwmQFYCgoqGgacK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blqqP9/btrQOO2Ia75/XwOCnYFtwmQFYCgoqGgacK/img.jpg&quot; data-alt=&quot;postman - import file&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blqqP9/btrQOO2Ia75/XwOCnYFtwmQFYCgoqGgacK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblqqP9%2FbtrQOO2Ia75%2FXwOCnYFtwmQFYCgoqGgacK%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;1077&quot; height=&quot;702&quot; data-filename=&quot;swagger-api-postman-import-04.jpg&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;702&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;postman - import file&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h3 data-ke-size=&quot;size23&quot;&gt;3. Raw text Import 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 다운로드한 JSON 파일의 텍스트를 복사해서 Raw text 탭을 열고 붙여 넣기 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;swagger-api-postman-import-07.jpg&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blhZY7/btrQRlFgAFH/kl2c0fGVpIPONH9mAaIYX0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blhZY7/btrQRlFgAFH/kl2c0fGVpIPONH9mAaIYX0/img.jpg&quot; data-alt=&quot;postman - import raw text&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blhZY7/btrQRlFgAFH/kl2c0fGVpIPONH9mAaIYX0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblhZY7%2FbtrQRlFgAFH%2Fkl2c0fGVpIPONH9mAaIYX0%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;912&quot; height=&quot;741&quot; data-filename=&quot;swagger-api-postman-import-07.jpg&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;741&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;postman - import raw text&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>ETC.</category>
      <category>postman</category>
      <category>REST API</category>
      <category>SWAGGER</category>
      <category>스웨거</category>
      <category>포스트맨</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/181</guid>
      <comments>https://fromnowwon.tistory.com/entry/postman-swagger#entry181comment</comments>
      <pubDate>Thu, 10 Nov 2022 09:58:43 +0900</pubDate>
    </item>
    <item>
      <title>[React 에러 일지] Already included file name ...differs from file name ...only in casing. (TypeScript)</title>
      <link>https://fromnowwon.tistory.com/entry/forceConsistentCasingInFileName</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트를 사용한 리액트 프로젝트에서 다음과 같은 에러가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2022-10-21 143020.jpg&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IqqqR/btrPeWgbHJD/PQTAg2382A5gKnKOYoW110/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IqqqR/btrPeWgbHJD/PQTAg2382A5gKnKOYoW110/img.jpg&quot; data-alt=&quot;Already included file name ...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IqqqR/btrPeWgbHJD/PQTAg2382A5gKnKOYoW110/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIqqqR%2FbtrPeWgbHJD%2FPQTAg2382A5gKnKOYoW110%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;497&quot; height=&quot;360&quot; data-filename=&quot;화면 캡처 2022-10-21 143020.jpg&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Already included file name ...&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;b&gt;tsconfig.json&lt;/b&gt;에서 &lt;b&gt;forceConsistentCasingInFileName&lt;/b&gt; 옵션을 &lt;b&gt;false&lt;/b&gt;로 변경하면 문제가 해결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666332784248&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;forceConsistentCasingInFileNames&quot;: false,&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forceConsistentCasingInFileName은 파일명에 일관된 casing를 강제로 적용하는 옵션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부 개발자는 대소문자를 구분하지 않고 파일명을 사용하고, 또 다른 일부 개발자는 대소문자를 구분한 파일명을 사용하게 될 경우 규칙에 어긋난다고 표시해주는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>React</category>
      <category>TypeScript</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/180</guid>
      <comments>https://fromnowwon.tistory.com/entry/forceConsistentCasingInFileName#entry180comment</comments>
      <pubDate>Fri, 21 Oct 2022 14:58:43 +0900</pubDate>
    </item>
    <item>
      <title>[React] Styled-components+TypeScript Props 전달 시 부모 컴포넌트에서 에러가 발생할 경우</title>
      <link>https://fromnowwon.tistory.com/entry/styled-components-props-error</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeScript와 Styled-components를 같이 사용하면서 아래와 같이 props 스타일을 지정해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(styles.button.ts)&lt;/p&gt;
&lt;pre id=&quot;code_1665100502906&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export interface ButtonProps {
  size: string;
}

export const PrimaryButton = styled(StyledButton)&amp;lt;ButtonProps&amp;gt;`
  width: ${props =&amp;gt; `${props.size === 'block' ? '100%' : 'auto'}`};
`;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Login.tsx)&lt;/p&gt;
&lt;pre id=&quot;code_1665100780101&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Login = ({ size }: ButtonProps) =&amp;gt; {
	// ...
	
    &amp;lt;PrimaryButton size={size} type=&quot;submit&quot;&amp;gt;
      Login
    &amp;lt;/PrimaryButton&amp;gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 자꾸 부모 컴포넌트에서 에러가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(App.tsx)&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;styled-componet-error-app-component.png&quot; data-origin-width=&quot;1267&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CFJj2/btrNZlaVwqx/1KOUTV9Wccn6VvrUnwxoN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CFJj2/btrNZlaVwqx/1KOUTV9Wccn6VvrUnwxoN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CFJj2/btrNZlaVwqx/1KOUTV9Wccn6VvrUnwxoN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCFJj2%2FbtrNZlaVwqx%2F1KOUTV9Wccn6VvrUnwxoN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1267&quot; height=&quot;262&quot; data-filename=&quot;styled-componet-error-app-component.png&quot; data-origin-width=&quot;1267&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Property 'size' is missing in type '{}' but required in type 'ButtonProps'. ts(2741)&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 에러가 발생한 원인은 props가 optional 하다는 걸 명시하지 않았기 때문이다. 쉽게 말해, size라는&amp;nbsp; props를 사용할 수도 있고 사용하지 않을 수도 있는데 무조건 사용하도록 되어있기 때문에 에러가 발생한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 props 스타일을 지정했던 interface에 물음표 연산자(optional chaining)만 추가하면 간단하게 해결할 수 있다.&lt;/p&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;(styles.button.ts)&lt;/p&gt;
&lt;pre id=&quot;code_1665100979511&quot; class=&quot;typescript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export interface ButtonProps {
  size?: string; // 여기
}

export const PrimaryButton = styled(StyledButton)&amp;lt;ButtonProps&amp;gt;`
  width: ${props =&amp;gt; `${props.size === 'block' ? '100%' : 'auto'}`};
`;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>React</category>
      <category>Props</category>
      <category>styled-components</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/179</guid>
      <comments>https://fromnowwon.tistory.com/entry/styled-components-props-error#entry179comment</comments>
      <pubDate>Fri, 7 Oct 2022 09:04:54 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Spring Boot - Gradle 프로젝트 빌드하고 실행하기</title>
      <link>https://fromnowwon.tistory.com/entry/spring-boot-gradle-build-run</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Spring&amp;nbsp;Boot&amp;nbsp;-&amp;nbsp;Gradle&amp;nbsp;프로젝트&amp;nbsp;빌드하고&amp;nbsp;실행하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;0. 서버를 반드시 꺼준다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 터미널에서 해당 프로젝트 경로로 이동&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 명령어를 통해 빌드 시작&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MAC&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;./gradlew build&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Window&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;./gradlew.bat build&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MAC&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;./gradlew clean build&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Window&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;./gradlew.bat clean build&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clean 명령어를 사용하면 기존 build된 파일이 사라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. build 폴더가 생성되면 터미널에서 build/libs 경로로 이동&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;cd build/libs&lt;/code&gt;&lt;/p&gt;
&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;4. jar 파일이 생성된 걸 확인했다면 명령어로 실행한다.&lt;/b&gt;&lt;br /&gt;&lt;code&gt;java -jar 프로젝트명-0.0.1-SNAPSHOT-plain.jar&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  &quot;~.jar에 기본 Manifest 속성이 없습니다.&quot; &lt;/b&gt;에러가 발생할 경우&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성이 있는 패키지나 라이브러리 등을 포함하지 않고 단순한 jar 파일을 생성했기 때문에 발생하는 에러다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Intellij&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 우측 Gradle 탭 &amp;gt; 프로젝트명 &amp;gt; Tasks &amp;gt; BootJar&lt;/b&gt; 더블 클릭하여 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 터미널에서 build/libs 경로로 이동 후 &lt;code&gt;java -jar&lt;/code&gt; 입력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.&amp;nbsp;&lt;code&gt;h&lt;/code&gt; 입력 후 &lt;code&gt;Tab&lt;/code&gt; 눌러 Jar 파일이 자동 선택되도록 한 후 엔터하여 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;eclipse&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;export wizard &amp;gt; Java &amp;gt; Runnable JAR file&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Java</category>
      <category>Gradle</category>
      <category>Spring</category>
      <category>spring boot</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/178</guid>
      <comments>https://fromnowwon.tistory.com/entry/spring-boot-gradle-build-run#entry178comment</comments>
      <pubDate>Tue, 4 Oct 2022 15:37:16 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 피보나치(fibonacci) 수열을 반복 함수, 재귀 함수로 연산하기 + 재귀 함수의 단점</title>
      <link>https://fromnowwon.tistory.com/entry/fibonacci</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치수열을 반복 함수와 재귀 함수 두 가지 방법으로 연산해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;피보나치수열이란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 두 수의 합이 다음 수가 되는 수열을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1 + 1 + 2 + 3 + 5 + 8 + 13 + ...&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;반복 함수 사용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복 함수는 for 문이나 while 문을 사용해서 함수를 구축하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664345291333&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	
	public static int fibonacci(int number) {
		int one = 1;
		int two = 1;
		int result = -1;
		
		if (number == 1) {
			return one;
		} else if (number == 2) {
			return two;
		} else {
			for(int i = 2; i &amp;lt; number; i++) {
				result = one + two;
				one = two;
				two = result;
			}
		}
		return result;
		 
	}

	public static void main(String[] args) {

		System.out.println(fibonacci(10)); // 55
		
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;재귀 함수 사용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀 함수는 for 문과 while 문을 이용하지 않더라도 스스로 자기와 똑같은 형태의 함수를 호출함으로써 문제를 해결하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664345641553&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	
	public static int fibonacci(int number) {
		if (number == 1) {
			return 1;
		} else if (number == 2) {
			return 2;
		} else {
			return fibonacci(number - 1) + fibonacci(number - 2);
		}
		 
	}

	public static void main(String[] args) {

		System.out.println(fibonacci(10));
		
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 연산의 경우 재귀 함수를 사용하면 코드가 더 간결해 보이지만 반복 연산이 훨씬 많아지므로 비효율적이다. 위 코드의 경우 대략적으로 2의 10승 정도의 연산이 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;재귀 함수는 때에 따라서 간결한 코드를 제공하지만 연산하는 데에 더 많은 시간을 소비할 수 있기 때문에 주의해서 사용해야 한다.&lt;/b&gt;&lt;/p&gt;
  &lt;/div&gt;</description>
      <category>Java</category>
      <category>알고리즘</category>
      <category>재귀함수</category>
      <category>피보나치</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/177</guid>
      <comments>https://fromnowwon.tistory.com/entry/fibonacci#entry177comment</comments>
      <pubDate>Wed, 28 Sep 2022 15:22:23 +0900</pubDate>
    </item>
    <item>
      <title>[Vue] 뷰3, 개발 환경 준비</title>
      <link>https://fromnowwon.tistory.com/entry/vue-3-setting</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Vue 3의 기본 개발 환경 세팅을 해보자. 우선 npm을 사용하기 때문에 Node.js가 필수로 설치되어 있어야 한다.&lt;/p&gt;
&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;1. Node.js 설치 확인&lt;/b&gt;&lt;br /&gt;&lt;code&gt;node -v&lt;/code&gt;&lt;/p&gt;
&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;2. Vue cli 글로벌 설치&lt;/b&gt;&lt;br /&gt;&lt;code&gt;node install -g @vue/cli&lt;/code&gt;&lt;/p&gt;
&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;3. Vue 프로젝트 생성할 곳으로 이동하여 프로젝트 생성&lt;/b&gt;&lt;br /&gt;&lt;code&gt;vue create 프로젝트명&lt;/code&gt;&lt;/p&gt;
&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;4. 버전 선택&lt;/b&gt;&lt;br /&gt;&lt;code&gt;[Vue 3] babel, eslint&lt;/code&gt;&lt;/p&gt;
&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;5. 패키지 매니저 선택&lt;/b&gt;&lt;br /&gt;&lt;code&gt;Use NPM&lt;/code&gt;&lt;/p&gt;
&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;6. 서버 접속&lt;/b&gt;&lt;br /&gt;&lt;code&gt;npm run serve&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http://localhost:8080/으로 접속하면 화면이 출력된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;vue-setting.png&quot; data-origin-width=&quot;3104&quot; data-origin-height=&quot;1880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doyo2K/btrJ8ZCNE14/Z6pxJFwHxaAKyhK45yoXDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doyo2K/btrJ8ZCNE14/Z6pxJFwHxaAKyhK45yoXDk/img.png&quot; data-alt=&quot;vue 초기 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doyo2K/btrJ8ZCNE14/Z6pxJFwHxaAKyhK45yoXDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdoyo2K%2FbtrJ8ZCNE14%2FZ6pxJFwHxaAKyhK45yoXDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3104&quot; height=&quot;1880&quot; data-filename=&quot;vue-setting.png&quot; data-origin-width=&quot;3104&quot; data-origin-height=&quot;1880&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;vue 초기 화면&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;</description>
      <category>Vue</category>
      <category>vue</category>
      <category>세팅</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/175</guid>
      <comments>https://fromnowwon.tistory.com/entry/vue-3-setting#entry175comment</comments>
      <pubDate>Sun, 21 Aug 2022 20:49:55 +0900</pubDate>
    </item>
    <item>
      <title>VSCode 터미널 바로 꺼지는 현상 해결 방법</title>
      <link>https://fromnowwon.tistory.com/entry/VSCode-%ED%84%B0%EB%AF%B8%EB%84%90-%EB%B0%94%EB%A1%9C-%EA%BA%BC%EC%A7%80%EB%8A%94-%ED%98%84%EC%83%81-%ED%95%B4%EA%B2%B0</link>
      <description>&lt;script async src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3749995100298532&quot;
     crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이 광고 - 상단 --&gt;
&lt;ins class=&quot;adsbygoogle&quot;
     style=&quot;display:block&quot;
     data-ad-client=&quot;ca-pub-3749995100298532&quot;
     data-ad-slot=&quot;5363632735&quot;
     data-ad-format=&quot;auto&quot;
     data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VSCode에서 터미널 실행을 하면 켜졌다가 바로 꺼지는 현상이 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VSCode를 계속 다시 실행해봐도 같은 현상이 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 현상을 해결하기 위해서는 너무 간단해서 어이없지만 컴퓨터를 재부팅한 후에 다시 실행하면 해결된다.&lt;/p&gt;</description>
      <category>ETC.</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/174</guid>
      <comments>https://fromnowwon.tistory.com/entry/VSCode-%ED%84%B0%EB%AF%B8%EB%84%90-%EB%B0%94%EB%A1%9C-%EA%BA%BC%EC%A7%80%EB%8A%94-%ED%98%84%EC%83%81-%ED%95%B4%EA%B2%B0#entry174comment</comments>
      <pubDate>Sun, 21 Aug 2022 18:31:54 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript] 타입 검사를 주의해야 하는 이유 (typeof, instanceof)</title>
      <link>https://fromnowwon.tistory.com/entry/typeof-instanceof</link>
      <description>&lt;div id=&quot;set-cw&quot; class=&quot;set-cw&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어를 다루면서 타입 검사는 누구나 한 번씩 해보게 되는 과정이다. 아무리 간단한 애플리케이션을 개발한다고 해도 타입 검사는 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타입 검사의 어려움&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;typeof는 무적이 아니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeof 연산자는 문자열로 해당 타입을 출력해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1660562277587&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typeof '문자열' // 'string'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof 123 // 'number'
typeof Symbol() // 'symbol'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참조값의 타입&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자, 문자, boolean, null, undefined, bigInt, Symbol이 원시 값에 해당하며, 이 외에 모든 값은 참조값이다. 참조값은 typeof로 타입을 출력하는 데에 어려움이 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1660562846905&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyClass {}
typeof MyClass // 'function'

const str = new String('문자열');
typeof str // 'object'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;class는 'function' 타입으로 출력되며 Wrapper 객체로 원시 값을 생성하게 되면 'object'가 출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;Wrapper Object(래퍼 객체)&lt;/b&gt;&lt;br /&gt;원시 타입의 값을 감싸는 형태의 객체를 말한다.&amp;nbsp;&lt;br /&gt;number에 대응하는 Number(), string에 대응하는 String(), boolean에 대응하는 Boolean(), symbol에 대응하는 Symbol()이 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;null에 대한 이슈&lt;/h4&gt;
&lt;pre id=&quot;code_1660562648691&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typeof null // 'object'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;null의 타입은 'object'가 출력된다. 자바스크립트가 인정한 언어적 오류로, 자바스크립트가 계속 발전해오면서 수정을 할 수 없는 상황이라고 판단을 해서 그대로 유지하게 되었다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;instanceof 연산자도 무적이 아니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 프로토타입 체인을 검사하는 연산자이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660563277694&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 생성자 함수
function Person(name, age) {

    this.name = name;
    this.age = age;
    
}

const mike = new Person('mike', 31);
mike instanceof Person; // true

const m = {

    name: 'mike',
    age: 31,
    
};
m instanceof Person; // false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 instanceof에도 함정이 있다. 참조 타입의 경우 결국 최상위 프로토타입이 객체이므로 instanceof Object의 출력 값은 무조건 true이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660563643231&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const arr = [];
const func = function() {};
const date = new Date();

arr instanceof Array; // true
func instanceof Function; // true
date instanceof Date; // true

// 참조 타입은 결국 최상위 프로토타입이 객체이다.
arr instanceof Object; // true
func instanceof Object; // true
date instanceof Object; // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;보완&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조 타입을 출력할 땐 instanceof 대신 아래와 같은 방법을 사용해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1660563793260&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const arr = [];
const func = function() {};
const date = new Date();

Object.prototype.toString.call(arr); // '[object Array]'
Object.prototype.toString.call(func); // '[object Function]'
Object.prototype.toString.call(date); // '[object Date]'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 동적으로 변하는 언어이기 때문에 타입도 동적이다. 따라서 타입 검사에 주의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;[Udemy] 클린코드 자바스크립트&lt;/p&gt;
&lt;/div&gt;</description>
      <category>JavaScript</category>
      <category>instanceof</category>
      <category>typeof</category>
      <author>fnow</author>
      <guid isPermaLink="true">https://fromnowwon.tistory.com/173</guid>
      <comments>https://fromnowwon.tistory.com/entry/typeof-instanceof#entry173comment</comments>
      <pubDate>Mon, 15 Aug 2022 20:50:30 +0900</pubDate>
    </item>
  </channel>
</rss>