<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>웹 꼬딩 기록 </title>
    <link>https://coldrain.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 10 Jun 2026 08:28:35 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>coldrain-f</managingEditor>
    <image>
      <title>웹 꼬딩 기록 </title>
      <url>https://tistory1.daumcdn.net/tistory/4726345/attach/ca4d7272b538439992e5d2a480581728</url>
      <link>https://coldrain.tistory.com</link>
    </image>
    <item>
      <title>데이터베이스 기본 개념 정리</title>
      <link>https://coldrain.tistory.com/99</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데이터베이스란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스는 일반적으로 DBMS에 의해 제어되는 구조화된 데이터 저장소입니다. 데이터를 효율적으로 관리하기 위해 행과 열로 모델링 된 테이블을 사용합니다. 그리고 대부분의 경우 SQL 언어를 작성하여 데이터를 조회, 등록, 갱신, 삭제 등과 같은 제어 처리를 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터베이스와 테이블의 차이점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스는 데이터 저장소이고, 테이블은 데이터베이스 내에서 데이터가 저장되는 형태입니다.&lt;/p&gt;
&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;도서 관리 데이터베이스에는 사용자 정보를 저장하는 사용자 테이블과 도서 정보를 저장하는 도서 테이블 등이 존재한다고 가정합니다. 그리고 도서 테이블은 도서 제목, 출판일, 저자 등의 칼럼(Column)으로 구성되어 있으며 제목과 저자는 문자 형태로 저장할 수 있고 출판일 칼럼은 날짜 데이터만 저장될 수 있도록 설계되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;데이터 조회 &lt;/b&gt;SQL 구성요소&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;SELECT&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 조회할 때 사용하는 명령어입니다. SELECT 절 뒤에 테이블의 어떤 칼럼(Column)을 조회할 것인지 지정해 줄 수 있습니다.&lt;/p&gt;
&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;SELECT NAME, AGE&lt;/b&gt; FROM STUDENT&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; FROM 절 뒤에 조회할 테이블 명을 적어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학생(STUDENT) 테이블에서 이름(NAME)과 나이(AGE)를 조회하도록 칼럼을 지정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;FROM&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 조회하거나 삭제 작업을 수행할 때 어떤 테이블에서 수행할 것인지 지정할 때 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 기본적인 경우는 테이블 명을 명시해 주는데, 상황에 따라서는 서브 쿼리도 올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;HAVING&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 조회 시 그룹으로 묶고 싶을 때 GROUP BY 절을 사용하는 데, 이때 그룹 조건을 지정해 줄 때 사용하는 키워드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JOIN&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 테이블을 하나로 합칠 때 사용하는 키워드입니다. JOIN은 두 테이블 간의 JOIN 조건에 대해 교집합인 레코드를 가지고 테이블을 형성하는 INNER JOIM과 JOIN 조건에 대해 교집합 + 왼쪽에 있는 테이블의 레코드를 가지고 테이블을 형성하는 LEFT JOIN 등 다양한 JOIN절이 존재합니다.&lt;/p&gt;
&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;SELECT * FROM &lt;b&gt;VOCABULARY&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;INNER JOIN &lt;b&gt;CATEGORY &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ON VOCABULARY.ID = CATEGORY.VOCABULARY_ID&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 단어장(VOCABULARY) 테이블과 카테고리(CATEGORY) 테이블을 JOIN 하는 예시입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ON절 뒤에는 JOIN 조건을 적어줍니다. SELECT 뒤에 *는 모든 칼럼을 보겠다는 ALL의 의미를 갖고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ORDER BY&lt;/b&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;특정 칼럼을 오름차순 하고 싶을 땐 ASC를 사용하고 내림차순을 하고 싶을 땐 DESC를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SELECT * FROM STUDENT&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ORDER BY AGE DESC&lt;/b&gt;&lt;/p&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;nbsp;&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;SELECT * FROM STUDENT&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ORDER BY AGE&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 나이 오름차순 정렬&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 DBMS는 DESC과 ASC를 생략하면 자동으로 ASC가 됩니다.&lt;/p&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;SELECT * FROM STUDENT&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ORDER BY AGE ASC, NAME DESC&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 1차적으로는 나이 오름차순 정렬, 그중에서 같은 레코드는 이름 내림차순 정렬&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬 조건을 1차 조건, 2차 조건, n차 조건처럼 여러 개 줄 수도 있습니다.&lt;/p&gt;</description>
      <category>  CS 지식/  데이터베이스</category>
      <author>coldrain-f</author>
      <guid isPermaLink="true">https://coldrain.tistory.com/99</guid>
      <comments>https://coldrain.tistory.com/99#entry99comment</comments>
      <pubDate>Tue, 19 Sep 2023 09:57:27 +0900</pubDate>
    </item>
    <item>
      <title>소프트웨어 설계 정리</title>
      <link>https://coldrain.tistory.com/98</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정보처리기사 자격증 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;개인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;공부용으로 정리한 글입니다. 기출문제 전자문제집 CBT를 참고하면서 정리하고 있습니다. 문제를 풀 때마다 계속해서 내용 추가를 할 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;UML 순차 다이어그램&lt;/b&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;b&gt;순차 다이어그램은 행위 다이어그램으로 &lt;u&gt;동적 상호작용&lt;/u&gt;을 한다.&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 모델링 X, 동적 모델링 O&lt;/li&gt;
&lt;/ul&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;UML 다이어그램의 종류&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Package Diagram&lt;/li&gt;
&lt;li&gt;State Transition Diagram&lt;/li&gt;
&lt;li&gt;Deployment Diagram&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터베이스 설계의 표현 다이어그램&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Entity-Relationship Diagram (ERD)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;미들웨어&lt;/b&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;b&gt;사용자가 미들웨어의 정보 교환 방법 등의 &lt;u&gt;내부 동작을 쉽게 확인할 수 없어야 보안상 안전&lt;/u&gt;하다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;소프트웨어 컴포넌트를 연결하기 위한 준비된 인프라 구조를 제공한다.&lt;/li&gt;
&lt;li&gt;여러 컴포넌트를 1대 1, 1대 다, 다대 다 등 여러 가지 형태로 연결이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;메시지 지향 미들웨어&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지 기반의 비동기형 메시지 전달 방식 미들웨어&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;즉각적인 응답이 필요한 경우보다는 &lt;u&gt;다소 느리고 안정적인 응답을 필요로 하는 경우에 많이 사용&lt;/u&gt;한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;온라인 업무보다는 &lt;u&gt;분산 데이터 시스템의 데이터 동기를 위해 많이 사용&lt;/u&gt;한다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;익스트림 프로그래밍&lt;/b&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;b&gt;구조적 방법론이 아닌 &lt;u&gt;애자일 방법론 중 하나&lt;/u&gt;이다.&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;유스케이스(Use Case)의 구성 요소 간의 관계에 포함되는 것&lt;/b&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;일반화 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기능적 요구사항&lt;/b&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;u&gt;&lt;b&gt;실제로 어떻게 동작하는지에 관점을 둔 요구사항&lt;/b&gt;&lt;/u&gt;이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) 금융 시스템은 조회, 인출, 입금, 송금의 기능이 있어야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능에 대한 이야기이므로 기능적 요구사항이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;비기능적 요구사항&lt;/b&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;u&gt;&lt;b&gt;실제 수행에 보조적인 요구사항&lt;/b&gt;&lt;/u&gt;이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) 차량 대여 시스템이 제공하는 모든 화면이 3초 이내에 사용자에게 보여야 한다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;성능에 해당하므로 비기능적 요구사항이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;UI 설계 지침&lt;/b&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;접근성: 사용자의 직무, 연령, 성별 등이 고려된 다양한 계층을 수용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체지향의 다형성&lt;/b&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;오버라이딩(Overriding): 상위 클래스에서 정의한 일반&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>  자격증/  정보처리기사</category>
      <author>coldrain-f</author>
      <guid isPermaLink="true">https://coldrain.tistory.com/98</guid>
      <comments>https://coldrain.tistory.com/98#entry98comment</comments>
      <pubDate>Wed, 13 Sep 2023 10:32:16 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 관계 정리(1:1, 1:N, N:M)</title>
      <link>https://coldrain.tistory.com/97</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1:1(일대일) 관계&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1:1 관계는 레코드당 다른 테이블에 연결된 레코드가 &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;p data-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;한 명이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;여러 개의 사물함을 사용하고 있는 경우도 있겠지만 A라는 체육관에서는 무조건 회원 한 명당 하나의 사물함만 배정한다고 가정한다면 1:1 관계가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결혼도 마찬가지입니다. 다른 나라는 일부다처제인 경우는 1:1 관계가 아니지만, 한국은 일부 일처제 제도이므로 남자와 여자는 결혼이라는 관계에서는 1:1 관계입니다. 남자는 여러 명의 여자와 결혼할 수 없고, 반대로 여자도 여러 명의 남자와 결혼할 수 없기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1:N(일대다) 관계&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1:N 관계는 주로 &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;일반적인 RDBMS에서 1:N 관계를 표현할 땐 자식 테이블에 부모 테이블의 기본키(Primary Key)를 참조하는 외래키(Foreign Key) 칼럼을 추가하는 방식으로 표현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게시글과 댓글도 1:N 관계로 설계된 경우가 많습니다. 하나의 게시글은 0개 이상의 댓글이 달릴 수 있고 댓글은 무조건 하나의 게시글에 속해있습니다.&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;게시글 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 47.7907%; height: 55px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;게시글 번호(PK)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;제목&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;1&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: 50%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 50%;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;댓글 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 67.5581%; height: 94px;&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: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;댓글 번호(PK)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;게시글 번호(FK)&lt;/b&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;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Index를 B+Tree구조....&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;1&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;2&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;1&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;3&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;2&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;4&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;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;N:M(다대다) 관계&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 데이터베이스 관계 중 가장 복잡한 관계인 것 같습니다. A 입장에서 0명 이상의 B와 관계를 가질 수 있고, 반대로 B 입장에서도 0명 이상의 A와 관계를 가질 수 있는 관계를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대학교에서 학생이 전공과목 수강 신청을 한다고 가정해 보겠습니다. 먼저 학생 입장에서 생각해 보면 한 명의 학생은 여러 개의 과목을 수강신청 할 수 있습니다. 예를 들면 홍길동 학생은 데이터베이스와 자료구조를 수강신청하는 상황을 말합니다. 이렇게 봤을 때, 학생과 과목은 1: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;이번엔 반대로 과목 입장에서 생각해 보겠습니다. 데이터베이스라는 과목은 홍길동 학생이 수강 신청한 건 맞지만 홍길동 학생 이외에도 다른 학생들, 철수와 영희도 데이터베이스에 수강신청 할 수도 있습니다. 이렇게 봤을 때, 과목과 학생은 1: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;이렇게 양쪽 입장에서 서로가 서로에게 1:N 관계인 경우를 N:M 관계라고 합니다. RDBMS에서 N:M 관계를 표현할 때는 학생 테이블과 과목 테이블 중간에 수강신청이라는 관계 테이블을 하나 더 두고 학생과 수강신청을 1:N, 과목과 수강신청을 1:N으로 설계함으로써 N:M 관계를 표현하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수강신청 테이블은 학생 테이블의 기본키(Primary Key)를 참조하는 외래키(Foreign Key) 칼럼이 있고 과목 테이블의 기본키를 참조하는 외래키 칼럼도 있게 됩니다.&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;학생 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 41.7442%; height: 37px;&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: 37px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 37px;&quot;&gt;&lt;b&gt;학생 번호(PK)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 37px;&quot;&gt;&lt;b&gt;이름&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;1&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: 50%;&quot;&gt;2&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: 50%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 50%;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;과목 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 43.3721%; height: 36px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;과목 번호(PK)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;과목명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;1&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: 50%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 50%;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;수강 신청 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 46.3941%; height: 107px;&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: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&lt;b&gt;학생 번호(FK, PK)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.0522%; height: 20px;&quot;&gt;&lt;b&gt;과목 번호(FK, PK)&lt;/b&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;1&lt;/td&gt;
&lt;td style=&quot;width: 22.0522%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 22.0522%; height: 17px;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 22.0522%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 22.0522%;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;홍길동 학생과 김철수 학생이 데이터베이스와 자료구조 두 과목을 수강 신청했음을 알 수 있고 김영희 학생은 아직 아무런 과목도 수강 신청하지 않았음을 알 수 있습니다.&lt;/p&gt;
&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;</description>
      <category>  CS 지식/  데이터베이스</category>
      <author>coldrain-f</author>
      <guid isPermaLink="true">https://coldrain.tistory.com/97</guid>
      <comments>https://coldrain.tistory.com/97#entry97comment</comments>
      <pubDate>Mon, 11 Sep 2023 14:33:52 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 Key 종류(기본키, 후보키 등등)</title>
      <link>https://coldrain.tistory.com/96</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;유일성과 최소성&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;유일성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유일성이란 하나의 키(Key)로 유일한 행(Row)을 식별할 수 있는 성질을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주민등록번호는 생명이 태어나면&lt;span&gt;&amp;nbsp;&lt;/span&gt;한 명당 하나씩만 부여받기 때문에 전산상으로 실수가 있는 게 아닌 이상 절대 중복될 수 없습니다. 따라서 유일성을 갖고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이름이나 성별은 동일한 이름과 성별을 갖고 있는 사람들이 여럿 존재할 수 있기 때문에 유일성을 갖고 있지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;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;(이름)&lt;/p&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;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;rarr; 두 개를 묶어도 유일성을 갖는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;최소성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행(Row)을 유일하게 식별하는 데 있어서 반드시 필요한 속성으로만 구성되어야 하는 성질을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주민등록번호와 이름을 묶어서 키(Key)를 구성하게 되면 유일성을 만족하므로 행을 유일하게 식별할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 잘 생각해 보면 주민등록번호만 있으면 이름이 없더라도 유일성을 만족하기 때문에 행을 유일하게 식별할 수 있습니다. 따라서 이름은 반드시 필요한 속성이 아니기 때문에 최소성을 갖지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름을 빼고 주민등록번호만으로 키를 구성한다면 불필요한 속성은 없으므로 최소성을 갖게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;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;(주민등록번호, 이름)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 최소성을 갖지 않는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데이터베이스 Key 종류&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;슈퍼키(Super Key)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유일성을 갖고 있는 모든 칼럼(혹은 속성)은 슈퍼키가 될 수 있습니다. 유일성만 갖고 있으면 최소성을 갖고 있지 않아도 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;후보키(Candidate Key)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후보키(Candidate Key)는 유일성과 최소성을 모두 갖고 있어야 합니다.&lt;/p&gt;
&lt;p data-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;이름은&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;p data-ke-size=&quot;size16&quot;&gt;대신 이름을 빼버리고 (주민등록번호)만 가지고 키를 구성한다면 유일성과 최소성을 모두 만족하므로 후보키가 될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기본키(Primary key)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본키(Primary Key)는 후보키 중에서 설계자가 선택한 키입니다. 후보키 중에서 선택되었으므로 유일성과 최소성을 모두 만족합니다. 따라서 중복된 값을 가질 수 없습니다. 추가적인 특징으로는 NULL 값이 올 수 없습니다.&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;일반적인 RDBMS에서는 기본키를 설정하면 자동으로 인덱스(Index)를 생성하기 때문에 데이터를 빠르게 조회할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;대체키(Alternative Key)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대체키(Alternative Key)는 후보키가 두 개 이상인 경우 기본키로 선택되지 못하고 남은 후보키들을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;외래키(Foreign Key)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외래키(Foreign Key)는 다른 테이블의 기본키 칼럼과 연결되는 칼럼을 의미합니다. 관계형 데이터베이스에서는 1:1(일대일), 1:N(일대다), N:M(다대다)과 같은 여러 관계들이 존재합니다. 이러한 관계들을 표현할 때 외래키를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 책 테이블과 카테고리 테이블이 있다고 가정해 보겠습니다. 그리고 하나의 책은 여러 개의 카테고리를 가질 수 있다고 한다면 책과 카테고리는 1:N 관계가 되고 이를 표현할 때 외래키를 사용합니다.&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;책 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 50.347%; height: 60px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&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;책 번호(PK)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;책 이름&lt;/b&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;1&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;2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;카테고리 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 60.5814%; height: 74px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&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;카테고리 번호(PK)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;카테고리 이름&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;책 번호(FK)&lt;/b&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;1&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;1&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;2&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;1&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;3&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;2&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;1:N(부모와 자식) 관계에서의 외래키 칼럼은 N(자식)에 해당하는 테이블에 추가하면 됩니다. 그리고 외래키 값은 값은 부모가 누구인지에 대한 참조 값(부모의 PK 값)을 갖고 있으면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 외래키를 사용하여 관계를 표현하면 카테고리 테이블에서 외래키 값으로 부모가 누구인지 바로 알 수 있고 조인(JOIN)으로 두 테이블을 합쳐서 데이터를 조회해 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블을 분리하고 외래키로 관계를 표현하면 데이터의 무결성을 유지할 수 있다는 이점이 있습니다. 만약 테이블을 분리하지 않고 하나의 테이블에서 책 정보와 카테고리 정보를 모두 관리한다면 책 이름이 바뀔 경우 자식에 해당하는 모든 카테고리 수만큼 부모의 책 이름을 전부 갱신해줘야 하는데 이는 데이터의 무결성을 유지하기 매우 어려워진다고 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  CS 지식/  데이터베이스</category>
      <author>coldrain-f</author>
      <guid isPermaLink="true">https://coldrain.tistory.com/96</guid>
      <comments>https://coldrain.tistory.com/96#entry96comment</comments>
      <pubDate>Thu, 7 Sep 2023 13:54:41 +0900</pubDate>
    </item>
    <item>
      <title>[React Native] 일본어 한자에 후리가나 표시하기</title>
      <link>https://coldrain.tistory.com/93</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 React Native를 사용해서 일본어 단어 암기 토이 프로젝트를 진행하고 있던 중 한자에 후리가나를 표시해야 하는 상황에 봉착했다.&lt;/p&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나 Vue와 같은 웹 개발 언어는 HTML 5 태그인 &amp;lt;ruby&amp;gt; 태그를 사용해서 간단하게 일본어 한자 위에 후리가나(혹은 요미가나)를 표시할 수 있길래 React Native에서도 비슷한 게 있겠지~. 하는 마음으로 찾아봤지만... 알고 보니 React Native에선 &amp;lt;ruby&amp;gt; 태그와 같은 기능을 하는 게 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이번기회에 한자에 후리가나를 표시하는 것을 연구해 보기로 했고 그 과정을 기록해보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;연구 시작&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;일단 만들어보기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1693380484857&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Text, View, SafeAreaView } from 'react-native';

function Furi({ kanjiList, hiraganaList }) {
  return (&amp;lt;View style={{ display: 'flex', flexFlow: 'row', flexWrap: &quot;wrap&quot; }}&amp;gt;
    { kanjiList.map((kanji, index) =&amp;gt; {
      return &amp;lt;&amp;gt;
        &amp;lt;View&amp;gt;
          &amp;lt;Text style={{ fontSize: 22 * 0.5}}&amp;gt;
          	{hiraganaList[index]}
          &amp;lt;/Text&amp;gt;
          &amp;lt;Text style={{ fontSize: 22 }}&amp;gt;{kanji}&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
      &amp;lt;/&amp;gt;
    }) }
  &amp;lt;/View&amp;gt;)
}

export default function App() {
  return (
    &amp;lt;SafeAreaView&amp;gt;
      &amp;lt;Furi kanjiList={['韓', '国', '人']} hiraganaList={['かん', 'こく', 'じん']} /&amp;gt;
      &amp;lt;Furi kanjiList={['考', 'え', '方']} hiraganaList={['かんが', ' ', 'かた']} /&amp;gt;
      &amp;lt;Furi kanjiList={['大', '人', 'し', 'い']} hiraganaList={['おと', 'な', ' ', ' ']} /&amp;gt;
      &amp;lt;Furi kanjiList={['使', 'い', '方']} hiraganaList={['つか', ' ', 'かた']} /&amp;gt;
      &amp;lt;Furi kanjiList={['お', '見', '舞', 'い']} hiraganaList={[' ', 'み', 'ま', ' ']} /&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;116&quot; data-origin-height=&quot;169&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J85Mk/btssDQ4Hg4k/2tvJpkz7qQu3Db9QYdeCO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J85Mk/btssDQ4Hg4k/2tvJpkz7qQu3Db9QYdeCO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J85Mk/btssDQ4Hg4k/2tvJpkz7qQu3Db9QYdeCO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ85Mk%2FbtssDQ4Hg4k%2F2tvJpkz7qQu3Db9QYdeCO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;116&quot; height=&quot;169&quot; data-origin-width=&quot;116&quot; data-origin-height=&quot;169&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후리가나와 한자를 한 쌍으로 묶어주고 한자의 수만큼 가로로 이어 붙였다. 이렇게 쌍으로 묶어준 이유는 한자마다 히라가나의 개수가 다르면 히라가나가 계속해서 밀리기 때문에 히라가나를 원하는 위치에 배치할 수 없어서 쌍으로 묶어 후리가나와 한자의 넓이를 동일하게 가져가도록 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;한자와 후리가나 간격 조절하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1693524428784&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Text, View, SafeAreaView } from 'react-native';

function Furi({ kanjiList, hiraganaList }) {
  return (&amp;lt;View style={{ display: 'flex', flexFlow: 'row', flexWrap: &quot;wrap&quot; }}&amp;gt;
    { kanjiList.map((kanji, index) =&amp;gt; {
      return &amp;lt;&amp;gt;
        &amp;lt;View style={{ textAlign: 'center' }}&amp;gt;
          &amp;lt;Text style={{ fontSize: 24 * 0.5 }}&amp;gt;
            {hiraganaList[index]}
          &amp;lt;/Text&amp;gt;
          &amp;lt;Text style={{ fontSize: 24 }}&amp;gt;{kanji}&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
      &amp;lt;/&amp;gt;
    }) }
  &amp;lt;/View&amp;gt;)
}

export default function App() {
  return (
    &amp;lt;SafeAreaView&amp;gt;
      &amp;lt;Furi kanjiList={['韓', '国', '人']} hiraganaList={['かん', 'こく', 'じん']} /&amp;gt;
      &amp;lt;Furi kanjiList={['考', 'え', '方']} hiraganaList={['かんが', ' ', 'かた']} /&amp;gt;
      &amp;lt;Furi kanjiList={['大', '人', 'し', 'い']} hiraganaList={['おと', 'な', ' ', ' ']} /&amp;gt;
      &amp;lt;Furi kanjiList={['使', 'い', '方']} hiraganaList={['つか', ' ', 'かた']} /&amp;gt;
      &amp;lt;Furi kanjiList={['お', '見', '舞', 'い']} hiraganaList={[' ', 'み', 'ま', ' ']} /&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czpxkk/btssP9VjT5y/FW8KIrNuoVDLLACrVKqcrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czpxkk/btssP9VjT5y/FW8KIrNuoVDLLACrVKqcrk/img.png&quot; data-alt=&quot;개선 전, 후&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czpxkk/btssP9VjT5y/FW8KIrNuoVDLLACrVKqcrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fczpxkk%2FbtssP9VjT5y%2FFW8KIrNuoVDLLACrVKqcrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;324&quot; height=&quot;266&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개선 전, 후&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 코드는 후리가나의 위치가 맞는 것 같으면서도 잘 맞지 않는 느낌이 있었다. 후리가나가 두 글자인 경우엔 예쁘게 잘 맞았지만 한 글자인 경우엔 너무 왼쪽으로 치우치고 세 글자 이상인 경우엔 한자 위치에서 오른쪽으로 너무 치우치는 것 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위해서 후리가나와 한자를 감싸고 있는 View 컴포넌트에 textAlign: 'center'를 적용해서 후리가나와 한자에 가운데 정렬을 해줬다. 개인적으론 이전보다 훨씬 보기 좋아진 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Props를 객체 배열로 넘기기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1693534611273&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Text, View, SafeAreaView } from 'react-native';

function Furi({ furiData }) {
  return (
    &amp;lt;View style={{ display: 'flex', flexFlow: 'row', flexWrap: &quot;wrap&quot; }}&amp;gt;
      { furiData.map(data =&amp;gt; (
        &amp;lt;View style={{ textAlign: 'center' }}&amp;gt;
            &amp;lt;Text style={{ fontSize: 24 * 0.5 }}&amp;gt;
              {data.furi ? data.furi : ' '}
            &amp;lt;/Text&amp;gt;
       		&amp;lt;Text style={{ fontSize: 24 }}&amp;gt;{data.word}&amp;lt;/Text&amp;gt;
      &amp;lt;/View&amp;gt;
      ))}
    &amp;lt;/View&amp;gt;
  )
}

export default function App() {
  return (
    &amp;lt;SafeAreaView&amp;gt;
      &amp;lt;Furi furiData={[
        { word: '考', furi: 'かんが' },
        { word: 'え', furi: '' },
        { word: '方', furi: 'かた' }
      ]} /&amp;gt;

      &amp;lt;Furi furiData={[
        { word: '送', furi: 'おく' },
        { word: 'り', furi: '' },
        { word: '仮', furi: 'が' },
        { word: '名', furi: 'な' }
      ]} /&amp;gt;

      &amp;lt;Furi furiData={[
        { word: '大', furi: 'おと' },
        { word: '人', furi: 'な' },
        { word: 'し', furi: '' },
        { word: 'い', furi: '' }
      ]} /&amp;gt;

      &amp;lt;Furi furiData={[
        { word: '大人', furi: 'おとな' },
        { word: 'し', furi: '' },
        { word: 'い', furi: '' }
      ]} /&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한자 배열과 한자에 대응되는 후리가나 배열을 각각 Prop으로 넘겨주던 방식을 객체 배열 하나만 넘겨주도록 구조를 살짝 변경했다. 이전 방식 같은 경우엔 길이가 같은 한자 배열과 히라가나 배열이 둘 다 필요했는데 바뀐 방식은 배열 하나만 넘겨주면 되도록 변경해 줌으로써 문장이 길어질 경우 기존 방식보다 꽤나 체감될 정도로 사용하기 수월해질 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;첫 번째 한자는 left로 정렬하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1693539818198&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Text, View, SafeAreaView } from 'react-native';

function Furi({ furiData }) {
  return (
    &amp;lt;View style={{ display: 'flex', flexFlow: 'row', flexWrap: &quot;wrap&quot; }}&amp;gt;
      { furiData.map((data, index) =&amp;gt; (
        &amp;lt;View&amp;gt;
        &amp;lt;Text style={{ fontSize: 24 * 0.5, textAlign: 'center' }}&amp;gt;
          {data.furi ? data.furi : ' '}
        &amp;lt;/Text&amp;gt;
        &amp;lt;Text style={{ fontSize: 24, textAlign: index === 0 ? 'left' : 'center' }}&amp;gt;
          {data.word}
        &amp;lt;/Text&amp;gt;
      &amp;lt;/View&amp;gt;
      ))}
    &amp;lt;/View&amp;gt;
  )
}

export default function App() {
  return (
    &amp;lt;SafeAreaView&amp;gt;
      &amp;lt;Furi furiData={[
        { word: '考', furi: 'かんが' },
        { word: 'え', furi: '' },
        { word: '方', furi: 'かた' }
      ]} /&amp;gt;

      &amp;lt;Furi furiData={[
        { word: '送', furi: 'おく' },
        { word: 'り', furi: '' },
        { word: '仮', furi: 'が' },
        { word: '名', furi: 'な' }
      ]} /&amp;gt;

      &amp;lt;Furi furiData={[
        { word: '大', furi: 'おと' },
        { word: '人', furi: 'な' },
        { word: 'し', furi: '' },
        { word: 'い', furi: '' }
      ]} /&amp;gt;

      &amp;lt;Furi furiData={[
        { word: '大人', furi: 'おとな' },
        { word: 'し', furi: '' },
        { word: 'い', furi: '' }
      ]} /&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;281&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FzKQQ/btssJjkAeP0/nSKCjCRgDLVmePxwfPpxk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FzKQQ/btssJjkAeP0/nSKCjCRgDLVmePxwfPpxk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FzKQQ/btssJjkAeP0/nSKCjCRgDLVmePxwfPpxk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFzKQQ%2FbtssJjkAeP0%2FnSKCjCRgDLVmePxwfPpxk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;281&quot; height=&quot;234&quot; data-origin-width=&quot;281&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 글자 뒷부분에 있는 한자들은 간격이 떨어져도 그러려니 할 수 있을 것 같은데 첫 번째 글자는 맞춰주고 싶었다. 그래서 index를 체크하여 첫 번째 글자인 경우에만 한자의 textAlign을 &quot;center&quot;가 아닌 &quot;left&quot;로 적용했다.&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;긴 문장 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1693541606851&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function App() {
  return (
    &amp;lt;SafeAreaView&amp;gt;
      &amp;lt;Furi furiData={[
        { word: '5', furi: '' },
        { word: '月', furi: 'がつ' },
        { word: '1', furi: 'つい' },
        { word: '日', furi: 'たち' },
        { word: 'の', furi: '' },
        { word: 'メーデーに、', furi: '' },
        { word: 'パリでは', furi: '' },
        { word: '毎年', furi: 'まいとし' },
        { word: '働', furi: 'はたら' },
        { word: 'く', furi: '' },
        { word: '人', furi: 'ひと' },
        { word: 'たちが', furi: '' },
        { word: 'デモ', furi: 'でも' },
        { word: 'を', furi: 'を' },
        { word: '行', furi: 'おこ' },
        { word: 'なっています。', furi: '' },
      ]} /&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;334&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nt0EF/btssSEAZpms/hClzK6pjjbQUKH5nqukojK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nt0EF/btssSEAZpms/hClzK6pjjbQUKH5nqukojK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nt0EF/btssSEAZpms/hClzK6pjjbQUKH5nqukojK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnt0EF%2FbtssSEAZpms%2FhClzK6pjjbQUKH5nqukojK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;334&quot; height=&quot;166&quot; data-origin-width=&quot;334&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴 문장도 후리가나가 잘 적용되었고 넓이를 넘어서면 줄 개행이 되는 것도 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만... 가장 큰 문제점은 지금은 단어에 대응되는 furi 값을 직접 설정해 주면 되지만 나중에 DB에 저장하고 불러올 땐 어떻게 대응해야 할지 도저히 감이 잡히지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;후리가나 표시, 숨기기 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1693543363224&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 { Text, View, SafeAreaView, Button } from 'react-native';

function Furi({ furiData, isShow = true }) {
  return (
    &amp;lt;View style={{ display: 'flex', flexFlow: 'row', flexWrap: &quot;wrap&quot; }}&amp;gt;
      { furiData.map((data, index) =&amp;gt; (
        &amp;lt;View&amp;gt;
            &amp;lt;Text style={{ fontSize: 24 * 0.5, textAlign: 'center' }}&amp;gt;
              {!data.furi || !isShow ? ' ' : data.furi}
            &amp;lt;/Text&amp;gt;
            &amp;lt;Text style={{ fontSize: 24, textAlign: index === 0 &amp;amp;&amp;amp; 'left' }}&amp;gt;
              {data.word}
            &amp;lt;/Text&amp;gt;
      &amp;lt;/View&amp;gt;
      ))}
    &amp;lt;/View&amp;gt;
  )
}

export default function App() {
  const [isShow, setIsShow] = React.useState(true);

  return (
    &amp;lt;SafeAreaView&amp;gt;
      &amp;lt;Furi furiData={[
        { word: '5', furi: '' },
        { word: '月', furi: 'がつ' },
        { word: '1', furi: 'つい' },
        { word: '日', furi: 'たち' },
        { word: 'の', furi: '' },
        { word: 'メーデーに、', furi: '' },
        { word: 'パリでは', furi: '' },
        { word: '毎年', furi: 'まいとし' },
        { word: '働', furi: 'はたら' },
        { word: 'く', furi: '' },
        { word: '人', furi: 'ひと' },
        { word: 'たちが', furi: '' },
        { word: 'デモ', furi: 'でも' },
        { word: 'を', furi: '' },
        { word: '行', furi: 'おこ' },
        { word: 'なっています。', furi: '' },
      ]} isShow={isShow} /&amp;gt;

      &amp;lt;Button 
        title={isShow ? 'Hide' : 'Show'}
        onPress={() =&amp;gt; {setIsShow(!isShow)}} 
      /&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRNx2h/btssGxKCg27/KtB8NxohJBX4qdUZJklkMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRNx2h/btssGxKCg27/KtB8NxohJBX4qdUZJklkMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRNx2h/btssGxKCg27/KtB8NxohJBX4qdUZJklkMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRNx2h%2FbtssGxKCg27%2FKtB8NxohJBX4qdUZJklkMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;715&quot; height=&quot;256&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 단어 암기가 핵심이라서 문장 전체의 show, hide만 구현했지만 나중에 문장 해석이나 독해와 같은 기능이 필요해지면 특정 단어를 선택했을 경우 보이고 숨기도록 만들어보는 것도 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;앱에 임시 적용 해보기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;855&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xgrBf/btssN2KhvJy/6qTv5SX4KSY8hQfe0P395K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xgrBf/btssN2KhvJy/6qTv5SX4KSY8hQfe0P395K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xgrBf/btssN2KhvJy/6qTv5SX4KSY8hQfe0P395K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxgrBf%2FbtssN2KhvJy%2F6qTv5SX4KSY8hQfe0P395K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;314&quot; height=&quot;619&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;855&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;일본어 장음부(&lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;ー)나 특정 한자들은 높이가 맞지 않아서 간격이 일정하지 않게 보이는 경우가 있었는데, 폰트 문제였던 것 같다. 앱에 직접 적용해 보면서 천천히 해결해보려고 했는데 생각 이상으로 깔끔하게 나와서 놀랐다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Furigana NPM 사용&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1693804183477&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Text, View, SafeAreaView } from 'react-native';

const fit = [ 
     { w: '考', r: 'かんが' },
     { w: 'え', r: 'え' },
     { w: '方', r: 'かた' },
];

function Furi({ writingText, readingText, isShow = true }) {
  // const fit = furigana.fit(writingText, readingText, { type: 'object' });
  const reg = /[ぁ-ゔ]+|[ァ-ヴー]+[々〆〤]/
  return (
    &amp;lt;View style={{ display: 'flex', flexFlow: 'row', flexWrap: &quot;wrap&quot; }}&amp;gt;
      { fit.map((data, index) =&amp;gt; (
        &amp;lt;View&amp;gt;
            &amp;lt;Text style={{ fontSize: 24 * 0.5, textAlign: 'center' }}&amp;gt;
              {reg.test(data.w) ? ' ' : data.r}
            &amp;lt;/Text&amp;gt;
            &amp;lt;Text style={{ fontSize: 24, textAlign: index === 0 ? 'left' : 'center' }}&amp;gt;
              {data.w} 
            &amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
      ))}
    &amp;lt;/View&amp;gt;
  )
}

export default function App() {
  return (
    &amp;lt;SafeAreaView&amp;gt;
      &amp;lt;Furi
        writingText=&quot;考え方&quot; 
        readingText=&quot;かんがえかた&quot;
      /&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Furigana NPM:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/furigana&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.npmjs.com/package/furigana&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693804413973&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fit = furigana.fit(&quot;考え方&quot;, &quot;かんがえかた&quot;, { type: 'object' })

// result
fit = [ 
     { w: '考', r: 'かんが' },
     { w: 'え', r: 'え' },
     { w: '方', r: 'かた' },
]&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;Furigana 모듈의 fit() 함수를 호출하면 위와 같은 결과를 받아올 수 있다. 각 한자별로 후리가나와 대응시켜 주는데 덕분에 DB를 어떻게 설계해야 할지 걱정하지 않아도 될 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 모듈 사용의 단점은 &lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;大人와 같은 단어는 おと/な도 아니고 &lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;お&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;/&lt;/span&gt;とな도 아닌 두 한자를 묶어서 &lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;お&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;とな가 후리가나가 돼야 하지만 결과는 &lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;お&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;とな로 반환된다는 점이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;즉, 사용하면 매우 편리하긴 하지만 100% 신뢰할 수 없고 해당 라이브러리에 너무 의존하게 될 것 같아서 스토어에 출시해야 하거나 서비스를 해야 한다면 다른 대안점을 찾아봐야 할 것 같다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;후기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레이아웃 개념이 많이 부족한 상태였는데 이번에 일본어 한자에 후리가나 표시 하는 것을 연구해 보면서 Flex에 대한 기본 개념이 조금은 잡힌 것 같다. 하지만 지금 만들고 있는 앱에 다양한 상황에 직접 적용하기에는 개선돼야 하는 점들이 꽤나 보였다. 그 부분들은 앱의 기능들을 구현하면서 조금씩 개선해 나갈 생각이다.&amp;nbsp;&lt;/p&gt;</description>
      <category>  개발 공부/  React Native</category>
      <author>coldrain-f</author>
      <guid isPermaLink="true">https://coldrain.tistory.com/93</guid>
      <comments>https://coldrain.tistory.com/93#entry93comment</comments>
      <pubDate>Wed, 30 Aug 2023 16:28:14 +0900</pubDate>
    </item>
    <item>
      <title>Vue.js 3 Composition Style 타입스크립트 정리</title>
      <link>https://coldrain.tistory.com/89</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Props 타입 설정&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기본 Props 정의&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1690876068983&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;div&amp;gt;{{ props.message }}&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;{{ props.numbers }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;

interface Props {
    message?: string,
    numbers?: number[]
}

const props = defineProps&amp;lt;Props&amp;gt;();
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키워드 '?'를 붙이면 Optional 한 Prop이 되고 붙이지 않으면 Required 한 Prop이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Props Default 값 설정&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기본 타입 Default 값 설정&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1690876344807&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;div&amp;gt;{{ props.message }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;

interface Props {
    message?: string,
}

const props = withDefaults(defineProps&amp;lt;Props&amp;gt;(), {
    message: 'this is default message'
});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Props의 Default 값을 설정하려면 Vue에서 제공해 주는 withDefaults라는 컴파일러 매크로를 사용해야 한다. 첫 번째 인수는 defineProps&amp;lt;Props&amp;gt;() 매크로를 넣어주고 두 번째 인수는 객체를 정의하여 각 Prop별로 default 값을 설정해 주면 된다.&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;배열(Array) Default 값 설정&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1692592331018&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;div&amp;gt;{{ props.numbers }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
interface Props {
  numbers?: number[]
}

const props: Props = withDefaults(defineProps&amp;lt;Props&amp;gt;(), {
    numbers: () =&amp;gt; [1, 2, 3, 4, 5]
})
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열은 화살표 함수를 사용하여 default 값을 설정해 줄 수 있다고 공식문서에 나와있다.&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;객체 Default 값 설정&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1692591953208&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;div&amp;gt;{{ props.book.title }}&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;{{ props.book.author }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
interface Book {
  title: string,
  author?: string
}

interface Props {
  book?: Book
}

const props: Props = withDefaults(defineProps&amp;lt;Props&amp;gt;(), {
  book: (): Book =&amp;gt; ({
    title: 'The Black Cat',
    author: 'Edgar Allan Poe' // optional
  })
})

&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체도 배열처럼 default 값을 설정하려면 화살표 함수를 사용하면 되는데 추가로 반환 타입을 명시해 줘야 하는 것 같다.&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;Emits 타입 설정&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;부모에게 넘길 값이 있을 때 - 함수 미사용&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1692593136277&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
&amp;lt;button @click=&quot;handleSendClick&quot;&amp;gt;Send message&amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;

const emits = defineEmits&amp;lt;{
    (e: 'update:message', message: string): void
}&amp;gt;();

const handleSendClick = (): void =&amp;gt; {
    emits('update:message', 'send message');
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Child.vue&lt;/p&gt;
&lt;pre id=&quot;code_1692593221828&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
	&amp;lt;Child @update:message=&quot;message =&amp;gt; receivedMessage = message&quot; /&amp;gt;
	&amp;lt;div&amp;gt;{{ receivedMessage || '받은 메시지가 없음' }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { ref } from 'vue'
import Child from './Child.vue';

const receivedMessage = ref('');
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Parent.vue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;부모에게 넘길 값이 있을 때 - 함수 사용&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1692662887607&quot; class=&quot;xml&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
&amp;lt;button @click=&quot;handleSendClick&quot;&amp;gt;Send message&amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;

const emits = defineEmits&amp;lt;{
    (e: 'update:message', message: string): void
}&amp;gt;();

const handleSendClick = (): void =&amp;gt; {
    emits('update:message', 'send message');
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Child.vue&lt;/p&gt;
&lt;pre id=&quot;code_1692662878019&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
	&amp;lt;Child @update:message=&quot;receiveMessage&quot; /&amp;gt;
	&amp;lt;div&amp;gt;{{ receivedMessage || '받은 메시지가 없음' }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { ref } from 'vue'
import Child from './Child.vue';

const receivedMessage = ref('');

const receiveMessage = (message: string): void =&amp;gt; {
  receivedMessage.value = message;
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Parent.vue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 사용하지 않았을 때와 동일한 기능을 수행한다. 넘겨받은 값이 함수의 인수에 자동으로 주입(?)된다. 위 코드에서는 Child가 전송한 message가 receiveMessage() 함수의 첫 번째 인수인 message에 주입된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;부모에게 넘길 값이 없을 때&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1692593403095&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
&amp;lt;button @click=&quot;handleSendClick&quot;&amp;gt;Send message&amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;

const emits = defineEmits&amp;lt;{
    (e: 'update:message'): void
}&amp;gt;();

const handleSendClick = (): void =&amp;gt; {
    emits('update:message');
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Child.vue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넘길 값이 따로 없다면 e만 설정해 주면 되고 emits()을 할 때에도 넘겨줄 값이 없기 때문에 두 번째 인수를 생략해 주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1692593437365&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;Child @update:message=&quot;receivedMessage = 'update message'&quot; /&amp;gt;
  &amp;lt;div&amp;gt;{{ receivedMessage || '받은 메시지가 없음' }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { ref } from 'vue'
import Child from './Child.vue';

const receivedMessage = ref('');
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Parent.vue&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;Ref 타입 설정&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1692594538560&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;{{ message }}&amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;{{ number }}&amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;{{ numbers }}&amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;{{ languageCode }}&amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;{{ book.title }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { Ref, ref } from 'vue'

// 자동 추론: Ref&amp;lt;string&amp;gt;
const message = ref('Hello World!');

// Ref 타입 명시 - 기본 타입
const number: Ref&amp;lt;number&amp;gt; = ref(10);

// Ref 타입 명시 - 배열
const numbers: Ref&amp;lt;number[]&amp;gt; = ref([10, 20]);

// Ref 타입 명시 - 유니온 타입
const languageCode: Ref&amp;lt;&quot;ko&quot; | &quot;en&quot;&amp;gt; = ref('ko');

// Ref 타입 명시 - 객체
interface Book {
  title: string;
  author?: string;
}

const book: Ref&amp;lt;Book&amp;gt; = ref({
  title: 'The Black Cat'
});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ref의 타입 설정은 Ref&amp;lt;Type&amp;gt;을 사용하여 타입을 설정하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reactive 타입 설정&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1692660681026&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;{{ book.title }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { reactive } from 'vue'

interface Book {
  title: string;
  author?: string;
}

const book: Book = reactive({
  title: 'The Black cat'
})
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 Typescript 객체처럼 타입을 설정하면 된다.&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;computed 타입 추론&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자동 타입 추론&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1692661241788&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;p&amp;gt;{{ count }}&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;{{ doubleCount }}&amp;lt;/p&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { ref, computed } from 'vue'

const count = ref(10);

// 반환 값으로 타입 추론 - CoumputedRef&amp;lt;number&amp;gt;
const doubleCount = computed(() =&amp;gt; {
  return count.value * 2;
})
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;타입 명시&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1692661337925&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;p&amp;gt;{{ count }}&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;{{ doubleCount }}&amp;lt;/p&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { ref, computed } from 'vue'

const count = ref(10);

// 타입 명시 - ComputedRef&amp;lt;number&amp;gt;
const doubleCount = computed&amp;lt;number&amp;gt;(() =&amp;gt; {
  return count.value * 2;
})
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;이벤트 핸들러 타입 설정&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1692663837836&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
	&amp;lt;input type=&quot;text&quot; @change=&quot;handleChange&quot; /&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { Ref, ref } from 'vue'

const data: Ref&amp;lt;string&amp;gt; = ref('');

const handleChange = (e: Event) =&amp;gt; {
  console.log((e.target as HTMLInputElement).value);
}

&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;e의 타입을 Event로 설정하고 'as' 키워드로 타입을 명시해 줘야 하는 것 같은데 공식 문서에도 자세한 가이드가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 프로젝트를 진행하면서 필요한 부분을 그때그때 찾아봐야 할 듯하다.&lt;/p&gt;</description>
      <category>  개발 공부/  Vue</category>
      <author>coldrain-f</author>
      <guid isPermaLink="true">https://coldrain.tistory.com/89</guid>
      <comments>https://coldrain.tistory.com/89#entry89comment</comments>
      <pubDate>Tue, 1 Aug 2023 16:46:26 +0900</pubDate>
    </item>
    <item>
      <title>Python 문법 정리</title>
      <link>https://coldrain.tistory.com/88</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몫과 거듭제곱&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1690413693332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;print(10 // 2) # 몫: 5
print(2 ** 3) # 거듭제곱: 8&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가감승제 연산자(+, -, *, /)와 나머지 연산자(%)는 Java와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;List 자료형&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기본 문법&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1690415871678&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 선언 및 초기화
arr = [1, 2, 3, 4]

# 인덱스 접근
print( arr[0] ) # 1 출력
print ( arr[-1] ) #  4출력

# 값 재할당
arr[0] = 10
print( arr[0] ) # 10 출력
arr[0] = 1

# 슬라이싱 list[n:m] n부터 m앞까지
print( arr[0:2] ) # [1, 2] 
print( arr[0:-1] ) # [1, 2, 3]
print( arr[1:-1] ) # [2, 3]

# 리스트 초기화
arr.clear()

# 리스트 컴프리헨션
arr = [0] * 3
two_d_list = [[0] * 3 for _ in range(3)]
even_list = [i for i in range(1, 10) if i % 2 == 0]

print(arr) # [0, 0, 0]
print(two_d_list) # [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
print(two_d_list[0][0]) # 0
print(even_list) # [2, 4, 6, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List는 순서가 있는 선형 자료구조이고, Array처럼 인덱스를 사용해서 O(1)로 접근할 수 있다. 음수 인덱스, 슬라이싱, List Comprehension은 생소한 개념이긴 하지만 익혀두면 굉장히 유용할 듯하다.&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;리스트 CRUD 함수&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1690418938258&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr = [1, 2, 3]

# 맨 뒤에 추가
arr.append(4)
print(list) # [1, 2, 3, 4]

# 0번 index에 0삽입
arr.insert(0, 0) 
print(arr) # [0, 1, 2, 3, 4]

# 2번 index에 2삽입
arr.insert(2, 2)
print(arr) # [0, 1, 2, 2, 3, 4]

# 값으로 제거
arr.remove(2) # 중복 값은 맨 앞에 값을 찾아서 지운다.
print(arr) # [0, 1, 2, 3, 4]

# 인덱스로 제거
arr.pop(-1)
print(arr) # [0, 1, 2, 3]

# 맨 뒤에 값 꺼내기
arr.pop()
print(arr) # [0, 1, 2]&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;List 정렬 함수&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1690428882699&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr = [15, 32, 17, 12, 19, 47, 35]

# 오름차순 정렬 - 원본 변형
arr.sort()
print(arr) # [12, 15, 17, 19, 32, 35, 47]

# 내림차순 정렬 - 원본 변형
arr.sort(reverse = True)
print(arr) # [47, 35, 32, 19, 17, 15, 12]

# 오름차순 정렬 - 원본 변형X, List 반환
sorted_list = sorted(arr)
print(sorted_list) # [12, 15, 17, 19, 32, 35, 47]

# 내림차순 정렬 - 원본 변형X, Iterator 반환
reversed_list = reversed(arr)
print(reversed_list) # &amp;lt;list_reverseiterator object at 0xa405f8&amp;gt;
print(list(reversed_list)) # [12, 15, 17, 19, 32, 35, 47]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Dictionary 자료형&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1690429542333&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dict = {}
dict['apple'] = '사과'
dict['banana'] = '바나나'

print(dict['apple']) # 사과
print(dict['banana']) # 바나나

print(dict.keys()) # dict_keys(['apple', 'banana'])
print(dict.values()) # dict_values(['사과', '바나나'])

# for문으로 모든 key 순회
for key in dict.keys():
    print(key)

# for문으로 모든 value 순회
for value in dict.values():
    print(value)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key, value 쌍으로 이루어진 자료구조이다. Java의 Map과 유사하지만 값을 key를 이용하여 배열처럼 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;접근할 수 있어서 좀 더 사용하기 편한 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Set 자료형&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1690435128031&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a = set([1, 2, 3, 4])
b = set([4, 5, 6, 7])

print(a) # {1, 2, 3, 4}
print(b) # {4, 5, 6, 7}

# 교집합 
print(a &amp;amp; b) # {4}

# 합집합
print(a | b) # {1, 2, 3, 4, 5, 6, 7}

# 차집합
print(a - b) # {1, 2, 3}
print(b - a) # {5, 6, 7}

# 원소 추가
a.add(5) 
print(a) # {1, 2, 3, 4, 5}

# 원소 여러 개 추가
b.update([1, 2, 3]) 
print(b) # {1, 2, 3, 4, 5, 6, 7}

# 원소 삭제
a.remove(5)
print(a) # {1, 2, 3, 4}

# set을 이용하여 list 중복 제거
arr = [3, 3, 7, 7, 2, 2, 1, 1]
unique_numbers = list(set(arr))
print(unique_numbers) # [1, 2, 3, 7]

arr = [1, 1, 2, 2, 7, 7, 3, 3]
unique_numbers = list(set(arr))
print(unique_numbers) # [1, 2, 3, 7]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List는 순서가 중요하지만 Set은 순서가 중요하지 않다. 사실상 Set은 순서가 없다고 봐야 한다. [1, 2]와 [2, 1]은 서로 다른 리스로 간주하지만 Set은 순서가 중요하지 않기 때문에 집합 {1, 2}와 {2, 1}은 같은 Set이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 List는 중복된 값이 저장 될 수 있지만 Set은 중복을 허용하지 않는다. 2를 3개 넣는다고 가정하면, List는 [1, 2, 2, 2]가 가능하지만 Set은 무조건 {1, 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;List를 Set으로 변환하여 중복을 제거한 후 다시 List로 변환하면 항상 그런지는 모르겠지만 오름차순으로 반환되는 것 같다. 만약 항상 그렇다고 한다면 List의 중복을 제거하고 오름차순으로 만들고 싶을 때 set()을 이용하면 유용할 듯하다. 그리고 그냥 중복만 제거할 때에도 유용할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;in과 not in&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1690439304822&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# in과 not in
if 1 in [1, 2, 3]:
    print(&quot;List [1, 2, 3]에 1이 들어있음&quot;)

if 1 not in [2, 3]:
    print(&quot;List [2, 3]에 1이 들어있지 않음&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트에 특정 값이 들어있는지, 없는지 체크할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1690439898531&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# input()의 반환값은 문자열

# 정수 값 1개 입력
n = int(input())

# 실수 값 1개 입력
n = float(input())

# 문자열 입력
message = input()

# 정수 값 공백을 구분 문자로 한 줄로 여러 개 입력 (Ex: 1 2 3 4)
numbers = list(map(int, input().split()))&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;b&gt;내장 함수&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1691453475460&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print(sum(numbers)) # 55
print(max(numbers)) # 10
print(min(numbers)) # 1
print(max(30, 20, 10, 40)) # 40
print(min(30, 20, 10, 40)) # 10&lt;/code&gt;&lt;/pre&gt;</description>
      <category>  개발 공부/  Python</category>
      <author>coldrain-f</author>
      <guid isPermaLink="true">https://coldrain.tistory.com/88</guid>
      <comments>https://coldrain.tistory.com/88#entry88comment</comments>
      <pubDate>Thu, 27 Jul 2023 09:39:40 +0900</pubDate>
    </item>
    <item>
      <title>Refresh Token을 사용하는 이유</title>
      <link>https://coldrain.tistory.com/87</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Refresh Token을 사용하는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&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;Access Token은 브라우저(쿠키, 로컬 스토리지 등)에 저장하기 때문에 언제든지 탈취당할 가능성이 있다고 한다. 이러한 보안 문제점 때문에 대안으로 나온 개념이 Refresh Token이다.&lt;/p&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 Token의 유효기간을 짧게 설정하고, Refresh Token의 유효기간을 길게 잡아서 리소스에 접근할 때는 Access Token을 통해서 하고 Access Token의 유효기간이 만료되면 Refresh Token으로 Access Token을 재발급받는 형태의 메커니즘이다.&lt;/p&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 Token의 유효기간을 짧게 설정함으로써 Access Token을 탈취당했을 때 짧은 시간 동안에만 피해가 발생하도록 하는 방법인 듯하다.&lt;/p&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 Token의 탈취를 완전히 막을 순 없지만 탈취당했을 때의 피해 시간을 줄일 수 있다는 것 같다.&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;로그인 유지&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access Token이 탈취당했을 때 발생하는 피해를 줄이기 위해 토큰의 유효기간을 짧게 줄여버리면 사용자는 만료될 때마다 매번 다시 로그인해야 한다는 문제점이 생긴다. 만약 게시판 서비스라고 한다면, 사용자가 글을 쓰고 있는 와중에 Access Token의 만료 기간이 지나버릴 수 있을 것이다. 그리고 만료되고 난 후에 글쓰기 완료 버튼을 눌러버리면 서버는 해당 토큰을 유효한 토큰이 아니라고 간주해서 정상적인 처리가 되지 않고 로그아웃 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 로그인 유지에 대한 방안으로 Refresh Token을 사용할 수 있다. 사용자가 글을 쓰는 와중에 Access Token이 만료되어도 서버에서 Refresh Token을 검증하고 Access Token을 재발급해주기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Refresh Token을 탈취당한다면?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access Token의 만료기간을 짧게 설정해 놓음으로써 탈취당하더라도 피해 시간을 줄일 수 있다는 것은 이해했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 결국 Refresh Token도 탈취당한다면 Access Token 하나만 사용하고 만료기간을 길게 잡아놓는 거랑 뭐가 다르지? 하는 의문점이 생겼고 여러 자료들을 찾아보면서 나름대로 생각을 정리해 봤다.&lt;/p&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 Token의 만료기간을 짧게 설정해 놓으면 피해 시간을 줄일 수 있으므로 토큰의 만료기간을 짧게 설정해 놓는다. 그리고 짧게 설정해 놓으면 자주 로그인해야 한다는 문제가 생기니 Refresh Token을 사용한다.&lt;/p&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 Token과 Refresh Token 두 개를 사용하면 Access Token만 탈취당했을 경우엔 피해 시간을 줄일 수 있는 것이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Refresh Token을 탈취당한다면 답이 없다고 판단하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Refresh Token을 서버의 DB 혹은 Redis에 저장해 놓는다면 Refresh Token이 탈취되었을 경우 파기를 하는 등의 대처를 할 수 있는 여지가 생긴다.&lt;/p&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 Token은 서버에 무언가 요청을 할 때마다 네트워크 전송을 하지만 Refresh Token은 Access Token이 만료되고 재발급받는 시점에만 전송하도록 구성한다면 Access Token보다 &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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access Token만 사용하던 Refresh Token도 같이 사용하던 둘 다 탈취당할 가능성은 존재하므로 HTTPS를 적용한다거나, 토큰을 쿠키에 저장하고 있다면 httpOnly와 secure 옵션을 적용한다거나 하는 등의 탈취당하지 않을 노력을 해야 된다는 생각을 갖게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 자료를 찾아보니 사람들 마다 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Refresh Token에 대해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;생각하는 게 달랐다. 토큰 저장만 해도 클라이언트에만 저장, 클라이언트 + DB, 클라이언트 + Redis에 저장 등 다양했고 토큰 재발급 방법도 서버에서 직접 만료 시간을 체크하여 토큰을 재발급하여 응답해 준다거나, 만료되었다면 정상 응답을 해주지 않고 클라이언트에 재발급 요청을 하라고 한다거나 하는 등 정말 다양했다. 또한 만료 시간은 클라이언트에서도 체크가 가능하다며 서버에서 체크하지 않고 setInterval()을 사용하여 토큰이 만료되면 서버에 재발급 요청을 보내는 사람도 있었다. 아니면 API 요청 전에 항상 토큰이 만료되었는지 체크하고 만료되었다면 재발급 요청 후 다시 API를 요청한다.&lt;/p&gt;
&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>✏️ TIL (Today I Learned)</category>
      <author>coldrain-f</author>
      <guid isPermaLink="true">https://coldrain.tistory.com/87</guid>
      <comments>https://coldrain.tistory.com/87#entry87comment</comments>
      <pubDate>Tue, 25 Jul 2023 14:43:16 +0900</pubDate>
    </item>
  </channel>
</rss>