<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>s-yeoyul.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 06 Jan 2026 05:14:26 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>s-yeoyul.log</title>
            <url>https://velog.velcdn.com/images/s-yeoyul/profile/13b24267-3b24-4cec-a6e5-a730316d4104/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. s-yeoyul.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/s-yeoyul" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[1. ISA]]></title>
            <link>https://velog.io/@s-yeoyul/1.-ISA</link>
            <guid>https://velog.io/@s-yeoyul/1.-ISA</guid>
            <pubDate>Tue, 06 Jan 2026 05:14:26 GMT</pubDate>
            <description><![CDATA[<p>전자레인지나 TV, 혹은 자동차까지, 어떠한 가전 및 전자 제품을 구매하던 간에 사용 설명서(manual)이 들어 있다. 이는 제조사가 설계 및 구현한 제품의 기능을 사용자가 잘 숙지하게 하기 위해 존재한다. <strong>중요한 점은, 매뉴얼은 사용자 관점에서 쓰여진 글이라는 것이다.</strong> 우리가 전자레인지를 사용할 때 전자기파의 어떤 주파수 대역을 이용하는지 알 필요가 전혀 없다. 그저 돌릴 시간을 입력하고 확인 버튼을 누를 줄 알면 오케이다.</p>
<p>ISA(Instruction Set Architecture)란 컴퓨터를 사용하기 위한 매뉴얼을 의미한다. 여기서 컴퓨터란 CPU를 의미하는 것이라고 보아도 좋다. 우리가 매뉴얼을 보는 목적은 컴퓨터가 구체적으로 어떻게 구현되어 있는지 알기 위해서가 아니다. 몇 나노 공정을 했고 캐시 사이즈는 얼마며 최적화를 위한 어떤 기술이 적용되었는지 등은 우리가 알 필요가 없는 것이다. 매뉴얼은 컴퓨터의 사용자, 즉 프로그래머 입장에서 컴퓨터를 의도한대로 동작하기 위해 어떻게 명령해야 하는지를 아주 자세히 설명하고 있어야 한다. 프로그래머 입장에서 컴퓨터에 명령을 내리는 방법은 딱 하나 뿐이다. 명령어(=Instruction)을 입력하는 것이고, 이 때문에 컴퓨터의 매뉴얼을 Instruction Set Architecture라고 부른다.</p>
<p>프로그램은 여러 개의 명령어들이 모여 만들어진 것이고, 컴퓨터에는 이를 저장할 공간이 필요하다. 이를 메모리라고 부른다. 명령어는 메모리에서 실행될 수 없다. 명령어가 실행되는 공간은 CPU고, 따라서 CPU는 메모리로부터 명령어를 가져와야 한다. CPU와 메모리는 Bus로 연결되어, 실제 버스처럼 메모리에 있는 데이터를 CPU로, CPU에 있는 데이터를 메모리로 저장할 수 있게 도와준다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/92eba3b7-bda7-4387-afd5-853fc7d9c917/image.png" alt="">
도식화하면 위 그림과 같이 표현할 수 있다.</p>
<blockquote>
</blockquote>
<ol>
<li>명령어를 가져옴(Fetch)</li>
<li>CPU가 명령어를 해독(Decode)</li>
<li>CPU가 명령어를 실행(Execution)</li>
</ol>
<p>위 과정을 끊임 없이 반복하는 것이 CPU가 하는 일이며, 이러한 컴퓨터의 구조를 폰 노이만 아키텍쳐라고 부른다. 또한 CPU가 메모리에서 명령어를 읽어오기 때문에 필연적으로 발생하는 병목을 폰 노이만 병목이라고 부른다.</p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/f6ea1d05-b6c3-40a7-ba5d-1dd4b906ae92/image.png" alt=""></p>
<p>폰 노이만 병목을 줄이기 위해서는 버스를 통해 메모리에 접근하는 횟수를 최대한으로 줄이는 것이 좋을 것이다. 예를 들어 내가 명령어를 어디까지 읽었는지에 대한 정보를 메모리에 저장해놓는 것 보다는 그냥 CPU가 들고 있는게 훨씬 빠를 것이다. 이런 목적을 위해 CPU에 데이터를 저장할 수 있는 작은 메모리를 만들게 되었고, 이를 레지스터(Registers)라고 부른다. 레지스터가 저장된 공간을 흔히 레지스터 파일(Register File)이라고 부른다.</p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/74160da1-4e3d-4e44-92d7-8c4dc0a44e47/image.png" alt=""></p>
<p>게임보이도 마찬가지로 CPU와 메모리, 그리고 그 사이를 이어주는 Bus가 존재한다. 물론 그게 다가 아니다. 게임화면을 출력해줄 LCD 기판이 있어야 하며, 소리를 내줄 스피커가 있어야 한다. LCD 기판에는 Video signal을, 스피커에는 Audio signal을 공급해줘야 한다. 조이패드 입력도 처리해야 하며, 카트리지도 꽂을 수 있게 만들어야 한다. </p>
<p>기본적인 CPU/메모리를 제외한 기기를 주변기기(Periperhal Device)라고 부르고 일반적인 컴퓨터에서 NIC/GPU/SSD 등에 해당한다. 주변기기에 대한 내용은 미뤄두고, 먼저 CPU에만 집중해보자. </p>
<p>자, 이제 우리에게 게임보이 콘솔 하나가 주어 졌다고 하자. 우리가 게임보이에서 돌아가는 게임을 만들어보고 싶다고 하면, 뭘 읽어봐야 할까? 당연히 ISA를 읽어봐야 한다. 게임보이가 어떤 명령어 체계를 갖고 있는지 숙지하고 그에 맞춰서 프로그램을 짜야 한다. 일반적인 CPU(Intel, AMD, ARM 등)과 달리 닌텐도는 출시 당시 ISA가 공개되지는 않았으나 지금은 쉽게 찾아볼 수 있다(<a href="https://ia803208.us.archive.org/9/items/GameBoyProgManVer1.1/GameBoyProgManVer1.1.pdf?utm_source=chatgpt.com">링크</a>). 혹은 ISA는 아니지만 게임보이의 스펙에 대해 위키 형태로 잘 정리된 <a href="https://gbdev.io/pandocs">홈페이지</a>도 존재한다.</p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/fc0654fe-63b7-46c7-b303-6ba10587caf1/image.png" alt="">
위 그림에서 8-bit Microprocessor라고 표기되어 있는 부분이 게임보이의 CPU에 해당하는 부분이다. 위 그림은 게임보이의 구현이 어떻게 되어 있는지를 보여주고 있다. 그러나 프로그래머 입장에서 RAM의 크기가 얼마니 하는 것들은 중요치 않다. 우리는 명령어가 어떻게 되어 있는지, 레지스터는 몇 비트로 몇 개나 있는지가 더 중요하다.</p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/d9c9eb0e-ce73-422e-8056-04abb71bb882/image.png" alt=""></p>
<p>게임보이는 8bit 레지스터(A, B, C, D, E, F, H, L)와 16bit 레지스터(PC, SP) 2가지 종류의 레지스터를 갖는다. </p>
<p>8bit 레지스터들은 하나씩 사용되기도 하며,
<code>ex) ADD A, B</code>
두 레지스터가 묶여서 하나의 16bit 레지스터 처럼 사용되기도 한다.
<code>ex) LD BC, n16</code> </p>
<p>일반적으로 명령어는 3가지로 분류할 수 있다.</p>
<blockquote>
</blockquote>
<ol>
<li>산술 및 논리 연산 명령어(ADD, SUB, OR, AND, ...)</li>
<li>데이터 이동 명령어(LOAD, STORE)</li>
<li>분기 명령어(JUMP, BRANCH)</li>
</ol>
<p>1번의 동작은 자명하다. 2번은 어딘가에 저장된 정보를 가져오거나(=LOAD), 레지스터에 저장된 값을 어딘가에 쓰는 연산(=STORE)를 의미한다. 3번은 명령어를 순차적으로 읽지 않고 임의의 주소로 건너 뛰거나(=JUMP), 조건문에 따라 명령어를 순차적으로 읽을지 아니면 임의의 주소로 분기할지(=BRANCH) 결정하는 명령어를 의미한다. <code>for</code> 문이나 <code>if-else</code> 같은 고수준 문법이 3번 명령어들로 구현된다.</p>
<p>PC는 Program Counter를 의미하며, <strong>현재 읽고 있는 명령어의 주소가 저장되어 있는 레지스터</strong>를 의미한다. SP는 Stack Pointer를 의미하는데, 설명이 길어지기 때문에 여기서는 생략하도록 하겠다(<a href="https://velog.io/@msung99/%EC%8B%9C%EC%8A%A4%ED%85%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-4-2%EC%A3%BC%EC%B0%A8-4ngkpnns">참고</a>).</p>
<p>이제 예시로 ISA에서 명령어 하나를 가져와서 분석해보자.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/3db2b46b-7563-495d-91c6-624cdbb61653/image.png" alt="">
위 그림은 게임보이의 8bit Load Instruction에 대한 부분을 일부 캡쳐한 것이다. 
<code>LD r, r&#39;</code> 와 같이 명령어를 작성하고, <code>r&#39;</code> 에 저장된 값을 레지스터 <code>r</code> 에 저장하게 만드는 명령어를 의미한다고 되어 있다. 각 레지스터는 표와 같이 decoding이 되어 있다(ex) LD 111, 000 이면 LD A &lt;- B).</p>
<p>자세히 보면 CY, H, N, Z, CYCL이라는 칸이 존재한다. 
먼저 C(Y), H, N, Z는 Flag인데, 산술 연산의 결과를 저장해서 다음 명령어가 이를 보고 명령을 수행할 수 있도록 하는 1비트 레지스터라고 보면 된다. 게임보이에서는 F 레지스터를 비트 단위로 나누어 Flag를 구현하였다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/611ed4a3-07ef-4376-aac9-1185b8356eb3/image.png" alt="">
예를 들어 <code>XOR A, A</code> 명령을 수행하면 A에는 0이 저장되고, 연산 결과가 0이므로 Z flag가 1로 assert된다. 이후 <code>JP Z, a16</code> 명령을 수행하게 되면 <code>if(z == 1) goto a16;</code> 과 같은 기능을 수행하게 된다.</p>
<pre><code class="language-cpp">    u8 result = regs.a ^ reg_val;
    flags.z = (result == 0) ? 1 : 0;
    flags.n = 0;
    flags.h = 0;
    flags.c = 0;
    regs.a = result;</code></pre>
<p>위는 C++로 CPU의 동작을 에뮬레이션한 것이다. CPU는 위와 같은 동작을 하드웨어적으로 수행한다. 필자는 CPU가 명령어를 읽고 해석해서 실행하는 과정을 <code>step()</code> 이라는 함수로 <code>CPU</code> class 내의 member function으로 구현하였다.
즉 <code>main.cpp</code> 에서</p>
<pre><code class="language-cpp">while(1) {
    cpu.step();
}</code></pre>
<p>이 무한루프를 도는게 아주 원시적인 컴퓨터라고 보면 된다. 여기에 PPU, APU, 인터럽트 등을 갖다 붙이면 제법 훌륭한 시스템이 되는 것이다.</p>
<p>필자는 <code>step()</code> 함수를 전부 구현하는데 꼬박 4일이 소요되었다. CPU가 처리해야 될 모든 명령어를 코드로 작성해야 하기 때문이다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/36869554-8efe-40d6-9ca7-aca209a8c421/image.png" alt="">
위 그림과 같이 많은 명령어 각각의 기능을 구현해야 하고, 그 때마다 flag가 잘 set되는지, 기능이 잘 동작하는지를 검사해줘야 한다. (위와 같은 표가 하나 더 있다, <a href="https://izik1.github.io/gbops/">출처</a>)</p>
<p>엄청나게 큰 <code>switch-case</code> 문을 이용하여 <code>step()</code> 함수를 아래와 같이 구현해주었다. </p>
<pre><code class="language-cpp"> 236         case 1: // ADC A, r8
 237           {
 238             u8 carry = (flags.c) ? 1 : 0;
 239             u16 temp = regs.a + reg_val + carry;
 240             flags.z = ((temp &amp; 0xFF) == 0) ? 1 : 0;
 241             flags.n = 0;
 242             flags.c = (temp &gt; 0xFF) ? 1 : 0;
 243             flags.h = ((((regs.a &amp; 0x0F) + (reg_val &amp; 0x0F) + carry) &amp; 0x10) == 0x10) ? 1 : 0;
 244             regs.a = temp &amp; 0xFF;
 245             return (reg == 6) ? 8 : 4;
 246           }
 247         case 2: // SUB A, r8
 248         case 7: // CP A, r8
 249           {
 250             u16 temp = regs.a - reg_val;
 251             flags.z = ((temp &amp; 0xFF) == 0) ? 1 : 0;
 252             flags.n = 1;
 253             flags.h = ((regs.a &amp; 0x0F) &lt; (reg_val &amp; 0x0F)) ? 1 : 0;
 254             flags.c = (regs.a &lt; reg_val) ? 1 : 0;
 255             if(op == 2) regs.a = temp &amp; 0xFF;
 256             return (reg == 6) ? 8 : 4;
 257           }
 258         case 3: // SBC A, r8
 259           {
 260             u8 carry = (flags.c) ? 1 : 0;
 261             u16 temp = regs.a - (reg_val + carry);
 262             flags.z = ((temp &amp; 0xFF) == 0) ? 1 : 0;
 263             flags.n = 1;
 264             flags.c = (regs.a &lt; reg_val + carry) ? 1 : 0;
 265             flags.h = ((regs.a &amp; 0x0F) &lt; ((reg_val &amp; 0x0F) + carry)) ? 1 : 0;
 266             regs.a = temp &amp; 0xFF;
 267             return (reg == 6) ? 8 : 4;
 268           }
 269         case 4: // AND A, r8
 270           {
 271             u8 result = regs.a &amp; reg_val;
 272             flags.z = (result == 0) ? 1 : 0;
 273             flags.n = 0;
 274             flags.h = 1;
 275             flags.c = 0;
 276             regs.a = result;
 277             return (reg == 6) ? 8 : 4;
 278           }
 279         case 5: // XOR A, r8
 280           {
 281             u8 result = regs.a ^ reg_val;
 282             flags.z = (result == 0) ? 1 : 0;
 283             flags.n = 0;
 284             flags.h = 0;
 285             flags.c = 0;
 286             regs.a = result;
 287             return (reg == 6) ? 8 : 4;
 288           }</code></pre>
<p>코드를 보면 함수가 4, 8 처럼 integer 값을 리턴하고 있는 것을 알 수 있다. 이는 한 명령어를 실행하는데 걸리는 사이클 수를 의미한다. </p>
<p>다음 글에서는 Multi-cycle CPU를 통해 cycle 수를 왜 return해야 하는지를 설명해보겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[0. Nintendo Gameboy]]></title>
            <link>https://velog.io/@s-yeoyul/0.-Nintendo-Gameboy</link>
            <guid>https://velog.io/@s-yeoyul/0.-Nintendo-Gameboy</guid>
            <pubDate>Sun, 04 Jan 2026 05:52:44 GMT</pubDate>
            <description><![CDATA[<p>초등학교 1학년 때, 메이플스토리가 하고 싶었던 필자는 아버지께 부탁하여 당시 데스크탑에 메이플스토리를 설치하였다. 몇 시간 동안이나 설치가 지속되었고, 메이플 아일랜드에서 주니어 스톤볼을 잡고 바로 컴퓨터를 꺼야 했던 그 때의 아쉬움이 아직도 생생하다.</p>
<p>3년이 지난 후 2011년, 마인크래프트라는 게임의 플레이 영상이 유튜브에 올라오고 있었다. 친구들과 함께 하고 싶었던 나는 마인크래프트 1.5.2 서버 여는 법을 네이버에 검색해가며 버킷을 다운받고, 파일을 메모장으로 열고, true를 false로 바꿔가며 결국 서버를 열었다.</p>
<p>컴퓨터가 뭘까? 뭐가 어떻게 돌아가는 걸까? 그런 의문이 가슴 속에 자리잡고 있었다. 고등학교 때 컴퓨터개론이라는 전공서적을 보게 되어 홀린 듯이 사서 읽었다. 진법이니, 프로그래밍언어니, 당시에는 도저히 알아들을 수가 없었다.</p>
<p>무섭게 치솟고 있던 컴퓨터공학과의 인기 탓에 나는 전기정보공학부로 진학하였다. 기초회로이론, 전자기학, 신호 및 시스템 등 무자비한 전공필수에 나는 컴퓨터에 대한 호기심이 들 새도 없이 시달리고 있었다.</p>
<p>4학년이 되어서야 나는 컴퓨터조직론이라는 수업을 듣게 되었다. 그 수업은 내 오랜 의문에 대한 길고 긴 대답이었고, 내 마음 속에 다시 한 번 작은 불씨를 피워 주었다. </p>
<hr>
<p>이 시리즈는 그 수업의 내용을 기록하기 위해 연재될 것이다. 연재를 도와주기 위해 내 추억 속의 작은 닌텐도를 가져왔다. </p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/feda6189-d095-4601-b826-61f26eff4497/image.png" alt=""></p>
<p>닌텐도도 결국 작은 컴퓨터다(<a href="">임베디드 시스템</a>이라는 아주 멋진 이름이 있지만). 필자는 닌텐도 게임보이를 소재로 사용하여 일반적인 컴퓨터 구조에 대해 나름대로 정리하고 배운 바를 설명하고자 한다. 
<img src="https://velog.velcdn.com/images/s-yeoyul/post/adfdef55-fbaf-4972-8608-c5b0fae04c8b/image.png" alt=""></p>
<p>필자는 이번 방학의 목표가 C++기반 게임보이 에뮬레이터를 만들어 포켓몬스터 적 버전을 플레이하는 것이었다. 모든 코드를 최대한 AI의 도움 없이 작성하고자 노력하였고, 한 달 동안 도서관에 박혀 열심히 뚝딱거려서 목표를 달성할 수 있었다. 에뮬레이터는 <a href="https://github.com/s-yeoyul/gbemu">github</a>에 공개해놓았다.</p>
<hr>
<p>본격적인 연재를 시작하기에 앞서 간단한 Introduction을 진행하고자 한다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/c1f47a6f-d6d0-4bb3-9b3e-edc043bc440d/image.png" alt=""></p>
<p>위 그림은 컴퓨터 시스템의 계층 구조를 잘 드러내주고 있다. 컴퓨터가 뭔가? 에 대해 대답하기 위해서는 각 레이어 및 인터페이스에 대해 전부 이해하고 있어야 한다.</p>
<p>전부 이해하기는 어렵고 너무 복잡하다. 컴퓨터조직론, 혹은 컴퓨터구조(Computer Architecture)라고 불리우는 수업은 가장 중앙에 위치하고 있는 하나의 레이어에 대해 알려주는 수업이다. 아키텍처 위에는 운영체제 및 응용 프로그램 같은 소프트웨어가, 아래에는 회로 및 소자 수준의 하드웨어 레이어가 있다. 각 레이어가 너무 복잡하다보니, 현대에는 각 레이어의 전문가들이 모여 하나의 시스템을 설계하게 되었다. 즉 다른 레이어에 대해 전부 알 필요는 없고, 뭉뚱그려서 이해하기 쉽게 만들게 표현하여 의사소통을 하게 되고 이를 <strong>abstraction</strong>이라고 부른다.</p>
<p>우리가 살펴볼 아키텍쳐는 컴퓨터가 어떻게 동작하는지(=<strong>functionality</strong>)에 관한 일종의 약속을 정하고, 이를 위/아래 레이어에 알려주는 역할을 한다. 자동차를 예로 들면 엑셀을 밟으면 앞으로 나아가고, 브레이크를 밟으면 자동차가 멈춘다는 사실은 제조사와 운전자 모두에게 이미 약속된 사항이다. 엑셀을 어느 정도의 힘으로 밟아야 60km/h에서 100km/h로 올라가는지는 아키텍쳐의 영역을 벗어난다. 이는 자동차 엔진의 스펙 등을 고려해야 하는 마이크로아키텍쳐의 영역이다. </p>
<p>즉 아키텍쳐란 컴퓨터 시스템의 개념적인 구조 및 동작을 프로그래머 입장에서 묘사하는 것을 의미하고, 실제 컴퓨터 시스템이 어떻게 구현되어 있는지와는 무관하다.</p>
<p>LG 그램에서는 돌아가는 게임이 애플 M2 맥북에서는 지원되지 않는 경우를 들어본 적이 있을 것이다. 이는 근본적으로 두 컴퓨터의 아키텍쳐가 다르기 때문이다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/b8b2f40b-ae08-46a2-9d13-483aaab2b599/image.png" alt="">
위 사진을 보면 Ubuntu를 설치할 때 Intel or AMD 아키텍쳐인지 ARM 아키텍쳐인지에 따라 선택지가 나뉘어있는 것을 알 수 있다. 일반적으로 Windows에서는 Intel 아키텍쳐를, 애플 실리콘은 ARM 아키텍쳐를 사용한다. 아키텍쳐가 다르다는 것은 자동차로 치면 운전하는 방식이 아예 다르다는 것이다. 그렇기에 Intel 아키텍쳐에서 돌아가는 프로그램이 애플 실리콘에서 돌아갈리가 없는 것이다.</p>
<p>게임보이 역시 약속된 사항이 존재한다. 구체적으로 뭐가 어떻게 약속이 되어있는지 살펴보도록 하자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[다중우주에서의 사랑]]></title>
            <link>https://velog.io/@s-yeoyul/%EB%8B%A4%EC%A4%91%EC%9A%B0%EC%A3%BC%EC%97%90%EC%84%9C%EC%9D%98-%EC%82%AC%EB%9E%91</link>
            <guid>https://velog.io/@s-yeoyul/%EB%8B%A4%EC%A4%91%EC%9A%B0%EC%A3%BC%EC%97%90%EC%84%9C%EC%9D%98-%EC%82%AC%EB%9E%91</guid>
            <pubDate>Wed, 31 Dec 2025 10:41:10 GMT</pubDate>
            <description><![CDATA[<p>얼마 전 에브리씽 에브리웨어 올 앳 원스라는 영화를 봤다. 내가 평소에 흥미롭게 보는 웹툰 쿠베라와 유사한 점이 많기도 하고, 나에게 울림을 주는 장면들이 많아 글로 정리해보고 싶었다.</p>
<h2 id="0-다중우주란">0. 다중우주란?</h2>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/4d5872e3-1516-46eb-9b76-5ab390eeb89f/image.png" alt=""></p>
<p>여기서 이야기하는 다중우주란 가능성에 따라 우주가 분기하여 여러 개의 우주가 존재하는 것을 의미한다. 에브리씽 에브리웨어 올 앳 원스를 보면 생명체의 선택에 따라 하나의 우주가 여러 가지 갈래로 분기하는 장면이 나온다. Part 3의 초반부에서 주인공 에블린이 영수증을 왼쪽에 놓을지, 오른쪽으로 놓을지 고민하다가 양쪽의 우주를 겹쳐 보여주는 장면이 이를 잘 드러낸다고 할 수 있다. 이런 일상적인 선택에 의해서도 분기되는 우주니, 셀 수 없이 많은 다중우주가 존재할 것이다.</p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/e3fe6b1d-67fa-4d2a-9487-e67a461d6594/image.png" alt="">
웹툰 쿠베라의 3부에서도 다중우주라는 개념이 등장한다. 영화와 마찬가지로, 생명체의 선택에 따라 우주가 분기한다는 것이다.
다만 에브리씽 에브리웨어 올 앳 원스와 쿠베라가 다른 점은, 쿠베라에서는 가능성의 세계와 현실 세계가 명확히 구분된다는 것이다. 작중에서 가능성의 세계로 남겨진 우주는 붕괴한다고 언급된다. 즉, 현실로 판정된 단 하나의 세계선을 제외하면 가능성의 세계는 사라진다는 의미이다.
<a href="https://velog.velcdn.com/images/s-yeoyul/post/a999a9ce-ba2b-42ba-8662-ff62ac0d0fe7/image.png"></a></p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/6e4b6dc0-2b56-4aa9-b129-471d7585034a/image.png" alt="">
이러한 설정으로 인해 딜레마가 생긴다. </p>
<ul>
<li>가능성으로 남겨진 우주의 생명체들이 멸망하는 것이 정당한가?</li>
<li>가능성의 우주에 남겨진 생명체가 현실 우주를 대체하면 어떻게 되는가?</li>
</ul>
<p>더 근본적으로, <strong>가능성과 현실을 구분짓는 기준은 무엇인가?</strong></p>
<h2 id="1-수많은-우주의-수많은-나">1. 수많은 우주의 수많은 나</h2>
<p>에브리씽 에브리웨어 올 앳 원스에서 가장 중요한 인간관계 2개를 뽑으라면 &#39;에블린&#39;-&#39;조이&#39;와 &#39;에블린&#39;-&#39;웨이먼드&#39;일 것이다. 흥미로운 것은 수많은 우주에서 내 손가락이 핫도그가 되든, 내가 돌이 되어버리든 상관없이 그 관계성은 일관적으로 유지된다는 것이다. 에블린이 어떤 가능성의 우주에 가도 상응하는 그녀의 웨이먼드가 있다. 비록 그와 그녀가 이어지지 않은 우주도 있지만, 그 우주의 성공한 웨이먼드는 그녀와 소박하게 세탁소를 운영하는 우주를 꿈꾼다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/c5b1fcbe-8e48-449e-8edf-b2fcd92019d5/image.png" alt="">
하지만 그 말을 들은 에블린은 바로 그 빨래방을 운영하는 세계선의 에블린이었고, 크게 성공한 자신의 인생을 동경하고 있었다. 에블린은 이후 모든 날 모든 순간을 소중히 여기는 것이 중요하다는 것을 깨닫는다. 어떤 우주든 어떤 인생을 살든, 함께 존재하는 지금 이 순간이 가장 중요한 것이라는 메시지를 영화에서 일관적으로 계속 던져주는 것으로 느껴졌고 나에게는 굉장히 와닿았다.</p>
<p>또 한가지 흥미로운 점은 영화가 수많은 우주를 넘나들 정도로 스케일이 거대하지만 정작 그들이 묘사하는 범위는 굉장히 작다는 것이다. 메인 우주에서 국세청 직원으로 등장하는 디어드리가 처음에는 비중이 적은 줄 알았으나, 거의 모든 우주에 다양한 역할로 관객의 눈에 띄게 된다. 결국 우주가 아무리 많고 아무리 다양해도 한 개인에게 우주란 자신의 주변을 의미할 수 밖에 없다는 것이다. 이러한 측면에서 볼 때 웨이먼드는 멸망하는 세계를 구하기 위해 에블린에게 찾아왔지만, 에블린은 그런 대의보다는 그저 자신의 가족을 구하기 위해 고군분투하는 것 처럼 보인다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/af3d9553-dc74-4007-8044-4dd214429678/image.png" alt="">
쿠베라에서도 자신이 사랑하는 사람을 포함한 범위를 우주라고 지칭하는 경우를 자주 볼 수 있다. 그들에게는 우주를 구하는 것이 사랑하는 사람을 구하는 것과 같다. 앞서 언급했듯 쿠베라에서 가능성으로만 남겨진 우주는 멸망하기 때문에 이러한 상황에서의 사랑이 더욱 극적으로 표현되고 있다. 하나의 예시를 살펴보자. 적 챕터에서 가능성의 세계에 도착한 &#39;란&#39;은 자신의 아내인 &#39;라나&#39;와 아이들을 멸망으로부터 구해내기 위해 현실 세계로 넘어갈 것을 제안한다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/523c2ef4-e92d-40b6-b33c-b5170ba775ee/image.png" alt="">
<img src="https://velog.velcdn.com/images/s-yeoyul/post/6898c966-2e3c-4589-b84b-b85a274a58af/image.png" alt="">
그러나 라나는 원래 우주에 있을 자신과 아이들의 몸을 빼앗을 수 없다며 이를 거절한다. 다중우주에서는 관계성이 변화하지 않는다는 것이 전제되기 때문에, 차마 다른 우주의 자신의 몸을 빼앗는 선택은 내릴 수 없었던 것이다. 지금 이 순간이 가장 중요하지만, 그건 다른 우주의 나에게도 똑같을 것이기 때문에.</p>
<h2 id="2-다중우주로-표현된-거대한-사랑">2. 다중우주로 표현된 거대한 사랑</h2>
<p>앞서 에블린-웨이먼드의 관계를 이야기했지만, 사실 에브리씽 에브리웨어 올 앳 원스는 에블린과 조이의 이야기라고 봐도 과언이 아닐 정도로 둘의 서사가 중요하다. 딸을 몰아붙이는 엄마라는 설정은 주변에 있을 법한 흔한 설정이지만 다중우주 SF라는 장르가 이를 극적으로 만들어버린다. 메인 우주에 있는 에블린은 조이가 여자친구를 두고 있는 것을 못마땅해 하고 살좀 빼라며 딸을 몰아붙이지만, 다른 우주의 과학자 에블린은 딸이 다중우주를 넘나들며 모든 능력을 학습하도록 딸을 몰아붙이게 된다.<br><img src="https://velog.velcdn.com/images/s-yeoyul/post/969afddc-1980-42de-bf5b-0dfb779443e6/image.png" alt="">
쿠베라에서는 꿈이 다른 우주를 의미할거라는 추측이 있는데, 영화와 비슷하게 꿈을 이용하여 기술을 습득할 수 있다는 설정이 존재한다. 쿠베라에서는 긍정적인 의미로만 사용되는 기술이지만, 에블린은 자신의 딸을 어느 우주와 다름없이 끝까지 몰아붙여 결국 자신의 딸인 조이를 괴물 조부 투바키로 만들어 낸다. 조부 투바키는 다중우주에 있는 모든 자신에게 접속할 수 있으며, 그곳에서 일어나는 모든 일을 알 수 있다. 조부 투바키는 모든 것을 알게 되고 허무주의자가 되어 세상을 무로 되돌리려고 한다.
쿠베라에서 정확히 조부 투바키에 대응되는 인물이 존재한다. 앞서 쿠베라에서는 가능성의 우주가 붕괴한다고 했는데, 이 우주에 살던 생명체들의 원한이 뭉쳐 만든 괴물인 &#39;유타&#39;가 존재한다. 유타는 자신의 의지와는 상관 없이 뭉쳐진 원한 때문에 세계를 멸망시키게끔 움직인다. 
<img src="https://velog.velcdn.com/images/s-yeoyul/post/f233dec2-037b-412b-9ab2-c2d630298256/image.png" alt="">
한편, 영화에서 세계를 무로 돌리려는 조부 투바키를 막아서는건 가장 실패한 세계의 에블린이었다. 그녀는 남편 웨이먼드와 닮은 친절한 자세로 조부 투바키에게 다가가 그녀를 조이로 되돌려 놓았다. 
<img src="https://velog.velcdn.com/images/s-yeoyul/post/0c4abb7c-1104-4ac2-ac20-7ce688eb3d25/image.png" alt="">
에블린에게 대응되는 쿠베라 속의 인물인 리즈는 유타의 애인이다. 리즈도 에블린과 마찬가지로 가장 실패한 세계에 속해있다고 할 수 있다. 고향 마을이 폭격되고, 아버지가 살해당하고, 가장 믿었던 사람에게 배신을 당한다. 에블린과 조이가 모녀 관계이지만 세계의 존망을 두고 대립하였듯 리즈와 유타도 정확히 같은 이유로 대립하게 된다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/666f543d-3bcd-4a31-bd47-2f9672dd3120/image.png" alt="">
작중에서 유타가 가능성을 상징하는 존재라면, 리즈는 시간축을 상징하는 존재이다. 시간은 단 하나의 가능성을 선택하여 역사에 기록한다. 시간이 선택하지 않은 가능성의 우주들은 모두 에너지를 잃고 멸망하고 만다. 이러한 설정 때문에 둘의 사랑은 더욱 애절해진다. 자신에게 부여된 시간이라는 역할 때문에 수없이 많은 애인들을 모두 소멸시켜야 하는 운명인 것이다.
<a href="https://velog.velcdn.com/images/s-yeoyul/post/4550a9ba-cafc-4864-8aa2-2d3f06c0e9a5/image.png"></a></p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/b50d78fb-aa72-4a94-8d67-57631f5ef830/image.png" alt="">
결국 우주를 구하는 것은 사랑이라는 메시지를 영화와 똑같이 던지고 있는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[옛날 메이플스토리의 풀메소와 int 자료형]]></title>
            <link>https://velog.io/@s-yeoyul/%EC%98%9B%EB%82%A0-%EB%A9%94%EC%9D%B4%ED%94%8C%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%9D%98-%ED%92%80%EB%A9%94%EC%86%8C%EC%99%80-int-%EC%9E%90%EB%A3%8C%ED%98%95</link>
            <guid>https://velog.io/@s-yeoyul/%EC%98%9B%EB%82%A0-%EB%A9%94%EC%9D%B4%ED%94%8C%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%9D%98-%ED%92%80%EB%A9%94%EC%86%8C%EC%99%80-int-%EC%9E%90%EB%A3%8C%ED%98%95</guid>
            <pubDate>Mon, 16 Sep 2024 13:56:38 GMT</pubDate>
            <description><![CDATA[<h1 id="2147483647-">2,147,483,647 ?</h1>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/eefe30d0-734e-4136-b6f2-4dd4416c7db8/image.png" alt="">
<a href="https://blog.naver.com/srudskadl/220124707922">출처 블로그</a></p>
<p>그 시절 메이플스토리를 해본 사람이라면 2,147,483,647 이라는 숫자에서 무언가 향수를 느낄지도 모른다.
백만 단위도 크게 느껴졌던 나에게, 학교에서 배운 방법으로 4자리씩 끊어가며 본 결과 저 숫자가 21억이라는 어마어마한 숫자라는 걸 알았을 때 무언가 압도되는 느낌을 받았었다. 그래서 저 숫자가 기억이 난다.</p>
<p>시간이 지나고 잊고 살다가, int 자료형을 배우게 되면 저 숫자가 <code>2^31 - 1</code>이라는걸 알게 된다.</p>
<p>대부분의 32bit 운영체제에서 int, long type의 자료형은 4byte, 그러니까 32개의 bit를 저장 할 수 있다. 그런데 2^32는 계산해보면
<img src="https://velog.velcdn.com/images/s-yeoyul/post/c18d7370-3a68-4b01-bd6d-cd97107af33a/image.png" alt="">
2,147,483,648이 아니다. 왜 그럴까?</p>
<p>그 이유를 컴퓨터가 Integer를 encoding하는 방법을 통해 알아보도록 하자.</p>
<p>(후술할 내용은 CS:APP 3rd edition을 참고하였습니다.)</p>
<h2 id="1-integer">1. Integer?</h2>
<pre><code class="language-c">int num = 3;</code></pre>
<p>Integer는 수학 용어로 정수를 의미한다. 
그리고 CS에서의 Integer는 유한한 범위의 정수를 표현하는 _integral data type_을 의미한다.</p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/418d8fd7-c29a-468a-9b60-7f9e57df62d3/image.png" alt=""></p>
<p>위 표에 32비트 운영체제에서 integral data type의 range가 적혀 있다.
눈 여겨 볼 점은 음수의 범위가 양수의 범위보다 1만큼 크다는 것이다. 
아마 0 때문이라고 직관적으로 추측은 되지만, 왜 그런지 정확히 설명해보라고 하면 할 말이 없다.</p>
<h2 id="2-unsigned-encodings">2. Unsigned encodings</h2>
<p>위 표를 보면 알 수 있듯이 자료형은 음수 범위를 커버하는지에 따라 signed와 unsigned로 나뉜다. 그리고 signed인지 unsigned인지에 따라 정수가 encoding되는 방식이 다르다.
unsigned의 경우 우리가 일반적으로 decimal(10진수)을 binary(2진수)로 변환하는 방법을 따른다. 이를 <strong>Unsigned encoding</strong>이라고 한다.</p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/6b8ddeb6-d64d-44f4-80c5-32d7843c5e28/image.png" alt=""></p>
<p>(B2U: Binary to Unsigned mapping)
이는 우리의 일반적인 상식과 일맥상통한다. 근데 이제 -1을 어떻게 표현하지??</p>
<h2 id="3-twos-complement-encodings">3. Two&#39;s complement encodings</h2>
<blockquote>
<p><strong>Two&#39;s complement</strong> form: 
Interpreting <strong>the most significant bit</strong> of the word <strong>to have negative weight.</strong></p>
</blockquote>
<p>Most Significant bit, 즉 첫번째 비트는 음수로 본다는 뜻이다. 예를 들어 보자.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/c5920079-073b-484f-80c8-6c40d9ae5aa8/image.png" alt=""></p>
<p>(B2T: Binary to Two&#39;s complement)
예시를 통해 보면 이해가 쉽다.
이제 왜 음수 범위가 양수 범위보다 1만큼 큰지 이해가 되는가?
음수의 최댓값은 [100...000]이고 양수의 최댓값은 [011...111]이다. 이는 1만큼 차이가 난다.
조금 더 생각해보면 unsigned를 non-negative로 정의하면서 0과 양수가 하나의 집합으로 묶이게 되었다. 그래서 0 + 양수의 집합과 음수의 집합은 크기가 같다. 
non-positive를 unsigned로 정의한다면 양상은 반대가 될 것이다.</p>
<p>왜 two&#39;s complement라고 불릴까? 
예를 들어 -5를 표현할 때 [1011] = -8 + 0 + 2 + 1로 계산이 된다.
즉 -2^3에 더하는 방식이기 때문에 two&#39;s complement라고 부른다.</p>
<h2 id="4-그-외의-encoding-방법들">4. 그 외의 Encoding 방법들</h2>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/c50e23c5-678e-4b17-bd8d-6b67d84b93df/image.png" alt=""></p>
<p>반면 one&#39;s complement는 0이 [11...11]로 표현되고,
-x = [11...11] - x로 구해지기 때문에 one&#39;s complement라고 불린다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[백트래킹]]></title>
            <link>https://velog.io/@s-yeoyul/%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9</link>
            <guid>https://velog.io/@s-yeoyul/%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9</guid>
            <pubDate>Sun, 15 Sep 2024 14:00:35 GMT</pubDate>
            <description><![CDATA[<h1 id="백트래킹이란">백트래킹이란?</h1>
<p>처음 알고리즘을 모르고 백준 문제를 풀 때, 재귀와 백트래킹이 무엇이 다른지 그리고 DFS가 뭔지 알지 못해서 너무나 어려웠다.
특히 N과 M 문제를 끼워 맞추듯 풀었던 기억이 있는데.. 
이번 기회에 정리해보고자 한다.
<a href="https://www.acmicpc.net/problem/15649">15649 N, M(1)</a></p>
<p>문제는 간단하다. N개의 자연수에서 M개를 고른 수열을 모두 출력하라는 것이다.
개수를 구하는 것은 간단하다. N Permutation M을 구하면 되니까.
경우의 수를 모두 구하는 것도 직접 종이에 쓰면서 하면 전혀 어려운 일이 아니지만, 이를 코드로 구현하는 것은 그렇게 쉽지 않다. 특히 처음하는 경우에는 더더욱 그렇다.</p>
<p><strong>예시로 6개의 자연수에서 2개를 뽑아 중복 없는 수열을 만들어보자.</strong></p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/b339da7b-a96a-44ec-8046-41cd93b73f2f/image.png" alt=""></p>
<p>누구나 위와 같은 그림을 그릴 수 있다. 그리고 누구나 이렇게 하나하나 셀 것이다.
당연하게도 위와 같은 사고과정을 코드로 옮겨 주면 된다.</p>
<p>코드로 구현하기 전에 알고리즘을 먼저 말로써 표현해보자. 어떤 순서로 짜면 될까?</p>
<blockquote>
<ol>
<li>첫 번째 자연수 부터 시작한다. 
출력해야 하므로 어딘가에 저장해놓는다.</li>
<li>다음 자연수로 이동한다. 
중복을 허용하지 않으므로 자연수를 increment한다. 
마찬가지로 어딘가에 저장해놓는다.</li>
<li><strong>2개를 모두 골랐으므로, 이전 상태로 돌아간다.</strong></li>
<li>다시 자연수를 increment한다
...</li>
</ol>
</blockquote>
<p>여기서 3번이 백트래킹의 핵심이다. 탈출 조건에 도착했을 때 작업을 수행하고 이전 단계로 돌아가는 것. <strong>이전 단계를 당연히 기억하고 있어야 한다.</strong>
그렇기 때문에 방문 정보를 담을 변수가 따로 필요하다. <code>bool visited[]</code>를 이용하자.
그리고 탐색하는 과정이 DFS의 과정을 따른다. DFS를 모르더라도 괜찮다. 일단 위 알고리즘을 하나씩 코드로 구현하여 보자.</p>
<p>1~N까지 자연수를 M-th depth까지 탐색하는 함수를 선언하면 된다.
가장 먼저 <strong>argument</strong>를 어떻게 받을지 정해야 한다.
몇 번째 깊이인지 알려주는 <code>cnt</code> 변수와 지금 가리키는 자연수의 위치를 알려주는 <code>idx</code>변수를 argument로 받으면  된다.
<code>void dfs(int idx, int cnt)</code>
이렇게 선언하자. </p>
<pre><code class="language-cpp">void dfs(int idx, int cnt){
    if(cnt == m){
    // Print visited numbers
    }</code></pre>
<p>그리고 함수의 Body를 작성해야 한다.</p>
<ol>
<li>어딘가의 현재 idx의 자연수를 저장하고</li>
<li>자연수를 increment 시켜서 다음 depth로 넘어간다.(재귀)</li>
</ol>
<p><strong>3. 제일 깊은 곳을 찍고 돌아왔을 때 다음 자연수로 넘겨줘야 한다.</strong></p>
<p>그림을 통해 이해해보자.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/197d2d40-f63e-4be5-9e93-4f483ff013e7/image.png" alt=""></p>
<p>main 함수에서 <code>dfs(0, 0)</code>를 호출하면 하트의 위치에서 탐색을 시작할 것이다.
그렇다면 이제 6개의 화살표를 쏴줘야 한다. 1~6을 모두 탐색해야 한다. 
자연스럽게 for문으로 한 바퀴 돌려보자는 생각이 든다.</p>
<pre><code class="language-cpp">for(int i = 1; i &lt;= n; i++){
    dfs(i, cnt + 1); // depth++, i = current num.
    }</code></pre>
<p>해야할 일이 세가지 더 남았다.
자연수를 저장하고, 방문 표시를 남기고, 돌아왔을 때 다음 자연수로 넘겨줘야 한다.
저장은 전역변수 <code>int ans[]</code>를 이용하면 될 것이고, 방문 표시는 <code>visited = true</code>로 설정한다.
돌아왔을 때 다음 자연수로 넘겨주는 것이 핵심이다.</p>
<p>이를 이해하는 것이 제일 중요하기 때문에 그림을 통해 과정을 이해해보자.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/8f79642c-36a9-495a-b03f-66172d46fbf5/image.png" alt="">
먼저 깊이 1에서 1을 탐색한다. <code>ans</code>배열에 1이 저장되었다.
한 칸 더 내려가자.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/ff552741-88af-4b73-88d1-9e5bbfffa69d/image.png" alt="">
깊이 2에서 2를 탐색하고 2를 저장한다. 이때 cnt 값은 1이다.
한 칸 더 내려가면 탈출 조건에 걸려서 저장된 1, 2를 출력한다.
<code>return;</code> 되는 순간 <strong>어디로 돌아가는가??</strong>
깊이 1의 1을 가리키는 곳으로 돌아갈 것이다.</p>
<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/2d1a25cd-5d0c-4ed8-ba89-d19627ed71d2/image.png" alt="">
2는 방문이 완료되었으므로 다시 탐색해서는 안된다.
즉, for문에 추가되어야 하는 코드는 다음과 같다.</p>
<blockquote>
<ol>
<li>현재 i값이 방문 표시가 되어 있는지 먼저 확인</li>
<li>방문표시가 되어 있지 않다면 방문 표시를 하고 현재 i값을 ans에 저장한다.</li>
<li><strong>돌아 왔을 때 방문 표시를 해제한다.</strong></li>
</ol>
</blockquote>
<p>방문 표시를 해제해 줘야 백트래킹 알고리즘이다. 밑으로 내려가면서 끝까지 찍고 다시 돌아오는 과정을 모두 수행하는게 백트래킹인데, 다시 돌아올려면 방문 표시를 해제해 줘야 한다. 다시 돌아오면서 이전에 저장해놓은 값들에는 방문하지 않은게 되기 때문이다.</p>
<p>이를 그대로 옮기면,</p>
<pre><code class="language-cpp">for(int i = 1; i &lt;= n; i++){
    if(!visited[i]){
      visited[i] = true;
      ans[cnt] = i;
      dfs(i, cnt + 1);
      visited[i] = false;
    }
  }</code></pre>
<p>이런식으로 모든 경우의 수를 순회할 수 있다.
전체 코드는 다음과 같다.</p>
<pre><code class="language-cpp">#include &lt;bits/stdc++.h&gt;

using namespace std;

int n, m;

int ans[9];
bool visited[9];

void dfs(int idx, int cnt) {
  if (cnt == m) {
    for (int i = 0; i &lt; m; i++) {
      cout &lt;&lt; ans[i] &lt;&lt; &#39; &#39;;
    }
    cout &lt;&lt; &#39;\n&#39;;
    return;
  }
  for (int i = 1; i &lt;= n; i++) {
    if(!visited[i]){
      visited[i] = true;
      ans[cnt] = i;
      dfs(i, cnt + 1);
      visited[i] = false;
    }
  }
}

int main() {
  cin &gt;&gt; n &gt;&gt; m;
  dfs(0, 0);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[2024.07.13]]></title>
            <link>https://velog.io/@s-yeoyul/2024.07.13</link>
            <guid>https://velog.io/@s-yeoyul/2024.07.13</guid>
            <pubDate>Sat, 13 Jul 2024 11:26:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/s-yeoyul/post/41dcecbc-e84a-4f10-a52d-b46474dde5db/image.png" alt=""></p>
<p>이거 하다보니까 재밌다 크크
확실히 c++ 실력이 늘긴 느는것 같다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[1920] Binary Search]]></title>
            <link>https://velog.io/@s-yeoyul/1920-Binary-Search</link>
            <guid>https://velog.io/@s-yeoyul/1920-Binary-Search</guid>
            <pubDate>Wed, 10 Jul 2024 14:34:58 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/1920">백준 1920번</a>
시간초과 따위 신경쓰지 않았던 나는 문제를 보자마자 무지성 브루트포스 알고리즘으로 코드를 짜면서도 정답률을 보고 무조건 시간 초과가 뜨겠거니 했다. 결과는 예상한 대로...<img src="https://velog.velcdn.com/images/s-yeoyul/post/5c631e5c-7342-4ebe-a536-ac70b7946235/image.png" alt="">
문제 유형을 보니 <strong>이진 탐색</strong>이라고 분류되어 있었다. 그렇다면 배열의 원소를 찾는 과정에서 이진 탐색을 통해 시간 복잡도를 감소시키라는 이야기!</p>
<h2 id="1-binary-search">1. Binary Search</h2>
<p>c++ 내장 함수를 사용해도 상관 없으나 직접 구현해보았다! 
LaTeX 쓰는게 재밌어서 psuedocode 열심히 만들어 보았다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/b193161f-6299-4be0-979e-51f82dfc7bf7/image.png" alt="">
평균적으로 <code>O(log n)</code>의 time-complexity를 갖는다.</p>
<h2 id="2-solution">2. Solution</h2>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;algorithm&gt;

using namespace std;
bool binary_search(int arr[], int size, int target) { 
  int left = 0;
  int right = size - 1;
  while (left &lt;= right)
  {
    int med = (left + right) / 2;
    if (arr[med] &lt; target) left = med + 1;
    else if(arr[med] &gt; target)
      right = med - 1;
    else
      return true;
  }
  return false;
}

int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  int N = 0;
  cin &gt;&gt; N;
  int integer_list[N];
  for (int i = 0; i &lt; N; i++) {
    cin &gt;&gt; integer_list[i];
  }
  sort(integer_list, integer_list+ N);
  int M = 0;
  cin &gt;&gt; M;
  int check_list[M];
  for (int i = 0; i &lt; M; i++) {
    cin &gt;&gt; check_list[i];
  }
  /*
  for (int i = 0; i &lt; M; i++)
  {
    for (int j = 0; j &lt; N; j++){
      if (check_list[i] == integer_list[j]) {
        cout &lt;&lt; 1 &lt;&lt; &#39;\n&#39;;
        break;
      }
      if (j == N - 1) cout &lt;&lt; 0 &lt;&lt; &#39;\n&#39;;
    }
  }
  */ // O(n^2) search algorithm (brute-force)
  for (int i = 0; i &lt; M; i++)
  {
    if (binary_search(integer_list, N, check_list[i])) cout &lt;&lt; 1 &lt;&lt; &quot;\n&quot;;
    else
      cout &lt;&lt; 0 &lt;&lt; &quot;\n&quot;;
  }
}</code></pre>
<h2 id="3">3.</h2>
<p>메모리 초과가 떴었는데 이는 동적 배열 때문인 것으로 파악하였고, 정적 배열을 쓰니 해결!
시간 초과는 브루트 포스 -&gt; 이진 탐색으로 해결!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[11098] Pointer and Dynamic Array]]></title>
            <link>https://velog.io/@s-yeoyul/11098-Pointer-and-Dynamic-Array</link>
            <guid>https://velog.io/@s-yeoyul/11098-Pointer-and-Dynamic-Array</guid>
            <pubDate>Tue, 09 Jul 2024 14:18:05 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/11098">백준 11098번</a>
문제를 읽어 보니 배열의 사이즈를 cin으로 받고 싶어지는 상황이다.. 
입력의 사이즈가 정해지지 않은 상황이기 때문에 동적 배열을 선언할 필요가 있다고 생각했다. 예전에 배웠던 <strong>포인터와 동적 배열</strong>의 개념을 복습하면서, 이 문제를 풀어보기로 하였다.
2021-봄학기 정교민 교수님의 프로그래밍 방법론 수업 자료를 참고하였다.</p>
<h2 id="1-pointers">1. Pointers</h2>
<blockquote>
<p>Pointer definition: <strong>Memory address</strong> of a variable.</p>
</blockquote>
<p>Memory location은 RAM에 수치화 되어 저장되어 있고, Address는 변수의 이름으로 사용된다. 이러한 개념은 이미 
<strong>Call by Value VS Call by Reference</strong>를 배우면서 학습한 바가 있다. 간단하게 짚고 넘어가면..
CBV: 변수의 값을 참조한다(pass the <strong>value</strong> of a variable).
CBR: 변수의 주소를 참조한다(pass the <strong>address</strong> of a variable).
전자는 값만을 가져오는 shallow copy와 관련이 있고 후자는 값의 주소를 가져오는 deep copy와 관련이 있다. 값만 가져오는 방법은 actual variable을 변화시킬 수 없지만 주소를 가져오는 방법의 경우 actual variable을 변화시킬 수 있다.</p>
<p>포인터 개념은 Address에 관한 것이기 때문에 Call by Reference을 배운적이 있다면 이미 알고 있는 것이다.
변수명 앞에 &quot;<strong>***&quot;를 붙이면 포인터 변수를 선언할 수 있다.
포인터 변수가 아닌 ordinary 변수의 앞에 &quot;</strong>&amp;<strong>&quot;를 붙이면 변수의 값이 아닌 주소를 가리키게 된다.
&quot;***</strong>&quot;는 주소가 가리키는 값을, &quot;<strong>&amp;</strong>&quot;는 값이 저장된 주소를 나타낸다. 즉 서로가 서로의 inverse function이라고 생각할 수 있다.</p>
<pre><code class="language-cpp">int *p1;
int v1;
p1 = &amp;v1;</code></pre>
<p>일반적으로 변수가 선언되면 자동으로 메모리가 할당된다. 그러나 프로그래머가 직접 Heap(memory freespace)에 메모리를 할당시키는 방법이 있는데 이를 Dynamic Memory Allocation이라고 부른다. 자유롭게 메모리를 할당하고 해제할 수 있는 장점이 있으나 제거하지 못하면 memory leak이 발생한다.
c++에서 &quot;new&quot;, &quot;delete&quot; operator가 각각 메모리 할당과 해제를 도와준다. 
<img src="https://velog.velcdn.com/images/s-yeoyul/post/3c32d44d-1973-4e5f-a08c-f3c0e3fd316c/image.png" alt=""></p>
<h2 id="2-dynamic-arrays">2. Dynamic Arrays</h2>
<p>고정된 Size의 Standard array와 다르게 Dynamic Array는 코드를 짤 때 Size가 결정될 필요가 없고 runtime에서 결정된다. <code>cin &gt;&gt; n</code>으로 배열 사이즈를 받아야 하는 우리는 Dynamic Array를 떠올릴 수 있어야 한다.
그리고 Array Variable은 pointer Variable이다.
아래의 두 변수 모두 pointer variable이다.</p>
<pre><code class="language-cpp">int v[10];
int *p;</code></pre>
<p>배열 변수는 첫번째 indexed variable의 주소를 가리킨다. 이는 항상 상수이다. 즉 <code>const int*</code>에 더 가깝다.
Standard Array가 Size를 먼저 명시해야 했다면 Dynamic Array는 필요에 따라 Size가 늘어나거나 줄어들 수 있다!</p>
<h2 id="3-solution">3. Solution</h2>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;sstream&gt;
#include &lt;string&gt;

using namespace std;

int main() {
  int n = 0;
  cin &gt;&gt; n;
  string *answer = new string[n];

  for (int i = 0; i &lt; n; ++i) {
    int best_price = 0;
    string best_athlete;
    int size = 0;
    cin &gt;&gt; size;
    string line;
    getline(cin, line);
    for (int j = 0; j &lt; size; ++j) {
      int price;
      string name;


      if (getline(cin, line)) {
        istringstream iss(line);
        iss &gt;&gt; price;
        getline(iss &gt;&gt; ws, name);

        if (price &gt; best_price) {
          best_price = price;
          best_athlete = name;
        }
      }
    answer[i] = best_athlete;
    }
  }
  for (int k = 0; k &lt; n; k++) {
    cout &lt;&lt; answer[k] &lt;&lt; endl;
  }

  return 0; }</code></pre>
<p>+) <a href="https://www.acmicpc.net/problem/5635">5635번 문제</a>
거의 똑같은 문제이다. 그런데 string 라이브러리의 <code>getline</code>함수를 사용할 때, 첫 번째 getline 함수는 값을 받아오지 않는 것 처럼 보여서 위 solution에서는 단순히 2번 쓰는 것으로 문제를 덮어 뒀는데, 알고보니 cin의 표준 입력 버퍼에 <code>\n</code>이 남아있어 이를 인식하는 것이라고 한다.</p>
<pre><code class="language-cpp">cin.ignore();</code></pre>
<p>를 추가해 주면 깔끔해진다.</p>
<h3 id="5635-solution">5635. solution</h3>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;sstream&gt;
#include &lt;string&gt;

using namespace std;

struct Birthday {
  string name;
  int day;
  int month;
  int year;
};

int main() {
  int size = 0;
  cin &gt;&gt; size;
  string line;
  Birthday *answer = new Birthday[size];
  cin.ignore();

  for (int i = 0; i &lt; size; i++) {
    if(getline(cin, line)){
      istringstream iss(line);
      Birthday birthday;
      iss &gt;&gt; birthday.name &gt;&gt; birthday.day &gt;&gt; birthday.month &gt;&gt; birthday.year;
      answer[i] = birthday;
    }
  }
  int least_idx = 0;
  int great_idx = 0;
  for (int i = 0; i &lt; size; i++){
    if (answer[i].year &lt; answer[least_idx].year) {
      least_idx = i;
    } else if (answer[i].year == answer[least_idx].year &amp;&amp;
               answer[i].month &lt; answer[least_idx].month) {
      least_idx = i;
    } else if (answer[i].year == answer[least_idx].year &amp;&amp;
               answer[i].month == answer[least_idx].month &amp;&amp;
               answer[i].day &lt; answer[least_idx].day)
      least_idx = i;


  if (answer[i].year &gt; answer[great_idx].year) {
    great_idx = i;
  } else if (answer[i].year == answer[great_idx].year &amp;&amp;
             answer[i].month &gt; answer[great_idx].month) {
    great_idx = i;
  } else if (answer[i].year == answer[great_idx].year &amp;&amp;
             answer[i].month == answer[great_idx].month &amp;&amp;
             answer[i].day &gt; answer[great_idx].day)
    great_idx = i;
  }

  cout &lt;&lt; answer[great_idx].name &lt;&lt; endl &lt;&lt; answer[least_idx].name &lt;&lt; endl;
  return 0;
    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[1003] Dynamic Programming]]></title>
            <link>https://velog.io/@s-yeoyul/1003-Dynamic-Programming</link>
            <guid>https://velog.io/@s-yeoyul/1003-Dynamic-Programming</guid>
            <pubDate>Fri, 28 Jun 2024 14:00:48 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/1003">백준 1003번</a>
내가 처음으로 풀어본 백준 문제다.
아니 지금 24살인데 처음 풀어본다고..? (...)
군대 갔다오기 전 들은 c++ 수업을 다 까먹어서 지금 이러고 있다..
처음엔 그냥 피보나치 수열을 살짝 꼬아놨군 이라고 생각해서 그냥 바로 global variable 만들어가지고</p>
<pre><code class="language-cpp">int zero_count = 0;
int one_count = 0;</code></pre>
<p>이렇게 했는데 어? 안되네? 왜 시간 초과??
당황한 나는 문제 분류를 보았고 <strong>다이나믹 프로그래밍</strong>이라고 적혀있는 것을 보고 이게 뭐지 싶었다. 배운적 있나? 찾아보니 없다..
Dynamic Programming이란 무엇인가? 내가 여기저기 읽어보고 정리한 바는 다음과 같다.</p>
<blockquote>
<p>어떤 문제 해결을 위해서, 문제를 <strong>작은 문제로 나눈 뒤 그 해답을 재활용</strong>하는 기법이다.</p>
</blockquote>
<p>Dynamic.. 계속 생각하다 보니 왜 Dynamic이라는 이름이 붙은 것인지 궁금해졌다. Dynamic에 대해서 이해하려면 역시 Static 또한 알아야 한다.
Static은 말 그대로 정적, 이미 정해져 있다는 뜻이다. Compile time에 fixed / bounded 되어 있다고 생각하면 된다. 
그렇다면 Dynamic은 반대로 이해하면 된다. Complie time에서 fixed / bounded 되어 있지 않은 것이다. 즉 언제나 바뀔  수 있는 것이고, 이는 우리가 익히 알고 있는 Dynamic의 의미와 통하므로 이제서야 이해가 된다. 아하!</p>
<p>그럼 빠르게 1003번 문제로 넘어가 보자.
이 문제는 시간 제한이 걸려 있어 Static 하게 접근하면 무조건 시간 제한에 걸린다. Dynamic하게 접근하면 그냥 바로 풀린다. Dynamic Programming에서 문제를 잘게 쪼개는 것이 가장 중요하고, 이를 우리는 Recursion이라고 알고 있으며, 이 분야의 대표적 예시는 당연히 피보나치 수열이다. </p>
<p>이 문제에서 요구하는 &quot;f(0)&quot;과 &quot;f(1)&quot;의 호출 횟수는 몇 번 적어보면 감이 온다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/481d85e4-3928-4917-b0ef-7a5522595b61/image.png" alt="">
위 그림을 보면 알 수 있듯이 호출 횟수 역시 피보나치 수열을 따르므로 그냥 피보나치 수열 D.P로 하나 짠 다음 출력하면 끝! 코너 케이스 조심해서 짜면 오케이!</p>
<h3 id="내-코드">내 코드</h3>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;vector&gt;

using namespace std;

int fibonacci(int n) {
  if (n == -2) return 1;
  if (n == -1) return 0;
  if (n == 0 || n == 1) {
    return 1;
  }

  vector&lt;int&gt; dp(n + 1, 0);
  dp[0] = 1;
  dp[1] = 1;

  for (int i = 2; i &lt;= n; ++i) {
    dp[i] = dp[i - 1] + dp[i - 2];
  }

  return dp[n];
}

int main() {
  int T = 0;
  cin &gt;&gt; T;
  int n = 0;
  for (int i = 0; i &lt; T; i++) {
    cin &gt;&gt; n;
    cout &lt;&lt; fibonacci(n - 2) &lt;&lt; &quot; &quot; &lt;&lt; fibonacci(n - 1) &lt;&lt; &quot;\n&quot;;
  }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React..]]></title>
            <link>https://velog.io/@s-yeoyul/React</link>
            <guid>https://velog.io/@s-yeoyul/React</guid>
            <pubDate>Wed, 08 Nov 2023 06:38:31 GMT</pubDate>
            <description><![CDATA[<h1 id="1-get-start">1. Get start</h1>
<hr>
<pre><code class="language-terminal">npx create-react-app &lt;folder name&gt;</code></pre>
<p>프로젝트 폴더를 만들고 initialize한다.</p>
<pre><code>npx create-react-app &lt;folder name&gt; --template typescript</code></pre><p>(Typescript initialize)</p>
<pre><code>npm start
yarn start // Open http://localhost:3000 at browser</code></pre><p>react에서는 코드를 수정하면 자동으로 웹페이지가 reload된다. 
안되는 경우 IDE에서 저장(Ctrl+s)하면 바로 반영된다..!</p>
<pre><code>npm run build
yarn build</code></pre><p>웹 배포에 사용하는 명령어이다. 배포 환경에서 사용할 파일을 만들어 준다!</p>
<h2 id="npm-yarn">npm? yarn?</h2>
<p>갑자기 튀어나온 npm과 yarn은 무엇일까? 일단 둘다 package manager다.
npm은 node.js와 함께 제공되는 기본 패키지 관리자이고, yarn은 페이스북에서 npm 문제를 해결하기 위해 개발된 패키지 관리자이다. 성능이나 보안 면에서 yarn이 우세하다고는 하지만 두 관리자 모두 꾸준히 업데이트 되고 관리되고 있어 개인의 취향이라고 한다. 
예전 세미나를 들었을 때 뭐가 됐든 좋으니 하나만 정해서 그것만 써라고 하신게 기억난다. </p>
<h2 id="prettier">prettier</h2>
<p>협업할 때 코드의 간결함, 통일성, conflict 방지를 위해 prettier를 이용하여 항상 같은 양식을 유지하도록 하기 위해 초기에 설정해주어야 한다고 배웠던게 기억난다.</p>
<h1 id="2-basics">2. Basics</h1>
<h2 id="2-1-jsx">2-1. JSX</h2>
<p>JSX는 자바스크립트 문법을 HTML style로 작성할 수 있게 만들어주는 문법이다.
<a href="https://react.dev/learn/writing-markup-with-jsx">RTFM</a>
예전에는 HTML, CSS, Javascript가 별개의 분리된 파일 내에 있었지만, 웹이 발전하면서 rendering logic(Javascript)과 markup language(화면에 표시되는 구조를 만드는 언어, HTML)를 함께 관리하게 되었다.</p>
<blockquote>
<p><strong>Rules</strong></p>
<ol>
<li>2개 이상의 태그가 있으면 무조건 하나의 부모 태그로 묶여 있어야 한다. 보통 <code>&lt;div&gt;...&lt;/div&gt;</code>로 묶는다. <code>&lt;&gt;...&lt;/&gt;</code>로 크게 묶기도 한다(Fragment).</li>
<li>모든 Tag를 닫아야 한다. 내용이 없는 태그거나 img등 관습적인 경우 Self-closing tag도 자주 쓰인다.</li>
</ol>
</blockquote>
<pre><code class="language-jsx">&lt;img 
    src=&quot;https://i.imgur.com/yXOvdOSs.jpg&quot; 
    alt=&quot;Hedy Lamarr&quot; 
    class=&quot;photo&quot;
   /&gt;</code></pre>
<blockquote>
<ol start="3">
<li>camelCase를 적용한다. (컴포넌트는 PascalCase를 적용한다)</li>
<li>주석은 <code>{/* ... */}</code> 로 적는다. 중괄호가 있어야 함!! 태그 내에서는 <code>//...</code>로 적을 수 있다.</li>
<li><code>{}</code> 를 이용하여 javascript 문법을 적용할 수 있다.</li>
</ol>
</blockquote>
<h2 id="2-2-props-state">2-2. props, state</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[그림자의 이야기]]></title>
            <link>https://velog.io/@s-yeoyul/%EA%B7%B8%EB%A6%BC%EC%9E%90%EC%9D%98-%EC%9D%B4%EC%95%BC%EA%B8%B0</link>
            <guid>https://velog.io/@s-yeoyul/%EA%B7%B8%EB%A6%BC%EC%9E%90%EC%9D%98-%EC%9D%B4%EC%95%BC%EA%B8%B0</guid>
            <pubDate>Mon, 30 Oct 2023 08:53:01 GMT</pubDate>
            <description><![CDATA[<p>(정리하는중)</p>
<p>주인공은 어렸을 때 백일장에서 만난 여주인공을 잊지 못하고 있다. 그녀는 자신이 그림자에 불과하다고 말하고, 진짜 자신은 벽 넘어에 있는 도시에 있다고 한다. 
이후 여주인공은 연락이 끊겨버리고, 주인공은 여주인공을 잊지 못하고 살다 마흔 다섯이 되어 우연히 그 도시 속으로 빨려 들어간다, 그림자를 남겨 둔 채로.
그 그림자는, 역으로 현실(?)로 나와, 삶을 이어가고, 도서관이라는 공간에 이끌려 그곳에서 고야스 씨라는 인물을 만난다.
꿈에서 깬 것 처럼, 그림자는 그 공간을 무의식의 영역 너머로 보내버려 잘 기억하지 못한다.
그리고 도서관은 비밀이 있는 듯 하다. 고야스씨에 대해 이야기하지 않는 직원들, 지하의 장작 난로가 있는 방...
신기하게도 도서관 밖에는 사과나무가 있다. 그 도시에서, 소녀가 사과로 과자를 만들어 주었던 것이 문득 생각난다. 그리고 고야스씨의 손목시계에는 바늘이 없다.
꿈을 기억하지 못하는 것처럼 주인공의 생각은 무언가 거대한 벽에 막혀버린 듯 하다.</p>
<p>--
어느날 고야스씨가 주인공을 지하 정사각형 모양의 방으로 부른다. 장작불에 비춰진 그의 모습에는, 그림자가 없었다. 그는 이미 1년 전에 심장마비로 죽은 사람이었고, 주인공과 소에다 씨만 그를 볼 수 있었다. 
그림자를 잃어버린다는건, 어떤걸 의미하는 걸까. 
자기 자신과 그림자의 관계를 이해하는게 이 소설을 이해하는 핵심이라는 생각을 했다.
고야스씨의 시계의 바늘이 멈춰 있는 것, 그 도시의 시곗바늘 없는 시계, 제거되어 버린 그림자... 그 도시는 죽음이 내려앉은 도시가 아닐까 하는 생각이 들었다. 그렇다면 죽음의 도시에 산다는 것은 무엇을 의미하는 걸까?
문제가 점점 좁혀져 간다.</p>
<p>고야스씨는 30여년 전 결혼을 하고 아이도 가졌지만 불의의 사고로 아이를 잃고, 이어서 아내도 잃었다. 그 뒤로 베레모를 쓰고, 스커트를 입는 기행을 하고 점점 다른 사람이 된 것 처럼 보인다. </p>
<p>주인공과 고야스씨는 공통점이 있다. 바로 한 여자를 순수한 마음으로, 온전히 사랑했다는 것. 주인공은 열여섯의 나이에 그런 사랑을 만나고 헤어졌고, 삼십년 동안 그녀만큼 다른 여자를 사랑할 수 없었다. 고야스씨 또한 아내를 그렇게 사랑했고, 그래서 아내가 죽은 후 다른 여자를 사랑할 수 없었고, 주변에서 혼담이 오가는 것이 싫어 스커트를 입어 이상한 사람으로 위장하였다. 고야스씨는 이를 &#39;마음이 타버렸다&#39;고 표현하고, 둘도 없는 행복인 동시에 어찌보면 성가신 저주라고도 이야기한다.</p>
<p>도서관에는 매일 와서, 말도 없이 책만 주구장창 읽는 &#39;옐로 서브마린 소년&#39;이 있다. 말 자체를 하지 않는 아이인데, 어느날 주인공에게 편지를 건넨다.
그 편지에는 높은 벽에 둘러 쌓인 그 도시가 그려져 있었다.</p>
<p><strong>어느 한 사람을 수십년간 보지 못한다면, 우연한 재회의 순간에 눈치챌 수 있을까...??</strong></p>
<hr>
<p>(읽는중....)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java]]></title>
            <link>https://velog.io/@s-yeoyul/Java</link>
            <guid>https://velog.io/@s-yeoyul/Java</guid>
            <pubDate>Thu, 26 Oct 2023 04:13:27 GMT</pubDate>
            <description><![CDATA[<p>java는 대표적인 객체 지향 프로그래밍 언어로써, 현재도 아주 범용성 있게 사용되고 있다.</p>
<p>프로그래밍을 진짜 기초부터 다시 공부해보려고 하니... 무슨 언어를 공부할까 고민이 많았다. 이제 java를 선택한 이유는 다음과 같다.</p>
<blockquote>
<ol>
<li>배우기 쉬운 객체 지향 언어이며 전공 수업에서도 많이 쓰인다.</li>
<li>나중에 backend를 공부할 일이 있으면(kotlin, spring) java를 할 줄 아는게 편할 것 같다.</li>
<li>가장 인기있는 언어 중 하난데 그래도 java는 할 줄 알아야지.. 현재도 많이 쓰이고 이번 기회에 공부해 두는게 여러모로 편할 거 같아서!!</li>
</ol>
</blockquote>
<p>여담이지만.. 초등학생때 마인크래프트를 할 때 java를 설치해야 게임을 할 수 있었던 기억이 난다. 그땐 몰랐지 그게 이거라는걸.. 그때 공부해 놓을걸.. </p>
<p>java가 가상 머신을 사용한다, garbage collection, oop.. 뭐 어디서 주워들은 이야기는 많은데 사실 설명할 줄은 모른다!! 나중에 면접때 java랑 c++ 차이가 뭐에요 물어보면 대답 못할 것 같고, 그래서 나중을 위해 이렇게 글로 남겨서 해보려고 한다. </p>
<hr>
<h3 id="1-java-byte-codeclass">1. JAVA byte code(.class)</h3>
<p>byte code는 전체 컴파일 과정에서, 우리가 쓴 코드가 가상 머신이 알아먹을 수 있는 형태로 바뀐 것이다. javac라는 컴파일러에 의해 .java 코드가 .class로 컴파일 된다.
<img src="https://dinfree.com/lecture/language/img/java-1-2.png" alt="Github_Logo"></p>
<h3 id="2-jvmjava-virtual-machine">2. JVM(Java Virtual Machine)</h3>
<p>그럼 가상 머신이 뭘까? 이는 하드웨어적인 기계를 말하는 것이 아니라 가상의, 즉 소프트웨어를 말하는 것으로, <strong>특정 하드웨어나 운영체제에 구애받지 않고 보편적으로 작동할 수 있도록 설계</strong>된 것이다. kotlin 같은 언어도 우리가 보는 format은 다르지만 결국 byte code로 변환되어 JVM으로 들어가기 때문에 완벽하게 호환된다고 할 수 있는 것이다!</p>
<h3 id="3-jdkjava-development-kit">3. JDK(Java Development Kit)</h3>
<p>Java환경에서 개발하기 위해 컴파일러, 디버거가 들어간 개발 키트를 의미한다.
나는 최근에 출시한 JDK 21을 사용하기로 했다.</p>
<hr>
<p>그럼 Hello world 부터 보도록 하자
#2557. Hello world</p>
<pre><code class="language-java">public class Main {
    public static void main(String arg[]) {
        System.out.println(&quot;Hello World!&quot;);
    }
}</code></pre>
<p>(주의: 백준에 올릴 때는 class 이름을 Main으로 지정해야 함)
java로 hello world를 출력해 보았다. 
자바는 class(.class)단위로 프로젝트가 돌아간다. 프로젝트는 보통 여러개의 class파일로 돌아가게 된다.
class안에는 method들이 들어간다. 이는 다른 언어에서의 function과 유사하다. class가 작동하기 위해서는 main method가 필요하고 이는 위 코드에서</p>
<pre><code class="language-java">public static void main(String arg[])</code></pre>
<p>이다. </p>
<p>c++에서 배운 class/inheritance 개념과 매우 비슷하다. c++을 배웠던걸 잘 기억해보자.. class Pet을 선언하고 Dog, Cat 등으로 inherit 해주고 member variable/function을 만들었던 게 기억이 난다! 새로운 객체를 만들때는 constructor를 이용하거나 dynamic programming 방식으로 new Class() 를 이용하기도 했다. java에서도 마찬가지인데, java에서는 member function/variable을 method라는 이름으로, 선언된 하나하나의 객체들을 instance라고 부른다.</p>
<pre><code class="language-java">public class Pet {
    String name; // member variable

    public void getName() { // method
        System.out.println(name);
        }

    public void setName(String input) { // method
        name = input;
        }
    public static void main(String arg[]){ // main method
        Pet cat = new Pet(); // declare instance
        cat.setName(&quot;zizi&quot;); 
    }

}</code></pre>
<p><a href="https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8#">좋은 참고글을 찾았다..!!</a></p>
<p>jvm, garbage collection 등 자세한 내용은 나중에 적어보기로 하고 여기서는 먼저 아주 기본적인 것부터..!!</p>
<h3 id="4-기본-명령어">4. 기본 명령어</h3>
<h4 id="4-1-scanner">4-1. Scanner</h4>
<pre><code class="language-java">import java.util.Scanner;</code></pre>
<p>사용을 위해 먼저 Scanner class를 import 해야 한다.
Scanner class에 포함된 method는 다음과 같다.</p>
<table>
<thead>
<tr>
<th>method</th>
<th>기능</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Scanner.next()</strong></td>
<td>Token을 읽어옴(String type)</td>
</tr>
<tr>
<td><strong>Scanner.nextLine()</strong></td>
<td>Enter가 나올 때 까지 모든 Token을 한 덩어리로 읽어옴(String type)</td>
</tr>
<tr>
<td><strong>Scanner.nextInt()</strong></td>
<td>Token을 읽어옴(Integer type)</td>
</tr>
</tbody></table>
<p>(nextBoolean, nextDouble 등 모든 변수 타입에 대해 함수가 존재한다, 생략!)
<strong>Scanner는 기본적으로 Token 단위로 입력을 받는다!</strong></p>
<blockquote>
<p>Token: <strong>띄어쓰기, Tab, Enter</strong> 등으로 구분되어지는 하나의 요소를 의미함. 입력을 Tokenize 한다는 것은 Token 단위로 입력을 parsing 하겠다는 것!</p>
</blockquote>
<p>자료구조 들을 때 Tokenize 하라는 말 듣고, 그냥 파싱한다고 하면 되지 왜 저렇게 말하나 했다.  </p>
<p>(...작성중)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인 타임]]></title>
            <link>https://velog.io/@s-yeoyul/%EC%9D%B8-%ED%83%80%EC%9E%84</link>
            <guid>https://velog.io/@s-yeoyul/%EC%9D%B8-%ED%83%80%EC%9E%84</guid>
            <pubDate>Sun, 24 Sep 2023 02:43:13 GMT</pubDate>
            <description><![CDATA[<p>시간이라는 소재에 매력을 느껴, 홀린듯이 보게 되었다.</p>
<p>우리는 공간축으로는 이동이 자유롭지만, 시간축에서 탈선하는 것은 불가능하다.
그렇기에 시간을 다루는 소재는 무언가 경외심이 들고, 흥미롭게 느껴지는 것 같다.</p>
<p>이 영화에서 시간은 돈을 대체한다. 시간은 한 인간의 수명을 결정짓는 역할도 하지만, 재화의 역할도 수행하게 된다. 이 두가지 기능이 복합적으로 작용했을 때 발생하는 가장 큰 문제점이 무엇일까?
바로 <strong>재화가 고갈되면 죽는다</strong>는 것이다. 이러한 특징 때문에 이 영화는 사회의 빈부 격차 구조를 적나라하게 드러내게 된다. 주인공 커플이 이러한 사회 체제에 반하여 부의 재분배, 즉 시간의 재분배를 위해 탈선하게 되는 과정이 이 영화의 시놉시스라고 할 수 있겠다.</p>
<p>이 영화에 등장하는 대부분의 인물들은 시간에 귀속 되어 있다. 시간에 사로잡혀 하루 벌어 하루를 사는 빈민가 사람들, 시간을 지키려 하는 Time keeper들, 10년이라는 시간을 받고 바로 술에 탕진하고 죽은 주인공의 친구..
반면 이 영화에서 눈길이 가는 인물들은 모두 시간축에서 벗어나 있다. 영화 초반에 주인공에게 100년을 주고 자살한 인물이 대표적인 예시 되시겠다. 시간에 얽매이지 않고 자신의 삶을 본인이 결정하였다. 죽기 직전 그의 표정에는 시간에 대한 미련 따위 없어 보인다.
이때 주인공은 100년이라는 시간을 받았지만 역설적으로 시간축에서 벗어났다. </p>
<p>그 후 주인공은 시간을 훔쳐 빈민가에 재분배하고, 모두에게 시간이 동일하게 주어진 사회를 만들 것임을 암시한다.</p>
<p>어쩌면 남은 시간이 보이지 않기에 더욱 행복하게 살 수 있는게 아닐까 생각이 드는 오늘이다.</p>
<blockquote>
<p>인 타임에서 아웃 타임으로.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 협업]]></title>
            <link>https://velog.io/@s-yeoyul/React-%ED%98%91%EC%97%85</link>
            <guid>https://velog.io/@s-yeoyul/React-%ED%98%91%EC%97%85</guid>
            <pubDate>Fri, 26 Nov 2021 16:21:03 GMT</pubDate>
            <description><![CDATA[<p>협업하면서 조심해야 될 것 정리</p>
<ol>
<li>package 설치</li>
</ol>
<p>이거 때문에 혼자 끙끙댔다..
다른분이 설치한 패키지를 로컬에 받아오면서 <code>npm install</code> 로 설치했는데 무슨 생전 처음 보는 오류가..ㅜㅜ
<code>npm ci</code>로 동기화 하니 깔끔하게 해결!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git]]></title>
            <link>https://velog.io/@s-yeoyul/Git</link>
            <guid>https://velog.io/@s-yeoyul/Git</guid>
            <pubDate>Wed, 24 Nov 2021 15:56:17 GMT</pubDate>
            <description><![CDATA[<p>토이 프로젝트를 하면서 Git을 많이 쓸텐데.. 걱정이다 
맨날 브랜치 파고-&gt;로컬 작업-&gt;커밋-&gt;푸쉬-&gt;메인 브랜치에 PR-&gt;머지
이렇게 했는데, 이젠 git flow니 Angular니 양식에 맞춰서 착착 해야한다.
배우면서 정리해보자.</p>
<p><a href="https://gist.github.com/stephenparish/9941e89d80e2bc58a153">AngularJS Github convention</a></p>
<hr>
<p><em>(2023.11.10)~</em>
프로그래밍 방법론에서 git을 처음 배웠을 때, 실습 시간에 git에 관한 자료를 아무리 읽어봐도 이해가 되지 않았었던 기억이 난다. 그 후 반년이 지나 와플에서 React 세미나를 들을 때, 첫 과제로 PR을 날리는게 나왔을 때가 생각난다. 어려웠다. 과제, 프로젝트를 하면서 수없이 마주했던 conflicts.. 마감 기간에 쫒겨 만든 수많은 무질서한 hotfix branch들ㅋㅋㅋㅋ git을 마지막으로 쓴지 거의 2년이 넘어가는 지금, 막막하지만 다시 공부해보며 처음부터 정리해보고자 한다.</p>
<h2 id="1-branch">1. branch</h2>
<p><a href="https://git-scm.com/book/ko/v2/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EB%B8%8C%EB%9E%9C%EC%B9%98%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80">Git</a></p>
<p>처음 배웠을 때에는 가장 중심이 되는 branch가 master라고 배웠는데, 인종차별 이슈로 인해 main으로 바뀌었다고 한다. 이번에 포켓몬 도감을 만들려고 새로운 repositary를 하나 팠는데 역시 main 브랜치가 자동으로 생성되었다. 
일단 branch를 하나 만들어 보았다. 헤더 부분을 구현하고 있어서, header라는 branch를 하나 분기시켰다. 
<code>git branch &lt;branch_name&gt;</code>
위 명령어를 이용하면 새로운 브랜치를 생성할 수 있다. 
<code>git log</code> 명령어를 이용하여 commit history, HEAD의 위치 등을 알 수 있다. 
<img src="https://velog.velcdn.com/images/s-yeoyul/post/d7192965-f4ee-43e6-8ae8-408f9606b6e3/image.png" alt=""></p>
<p>HEAD가 main을 가리키고 있고 아직 commit한 내역이 없기에 initialize한 commit만이 존재한다. 
branch를 옮기려면 <code>git checkout &lt;branch_name&gt;</code> 명령어를 이용하면 된다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/09104d79-f57a-44ba-b5ab-2344089a562d/image.png" alt=""></p>
<p><code>git branch</code> 명령어를 이용하면, 전체 분기된 branch들의 목록을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/s-yeoyul/post/997476de-4b34-4b72-a279-da4866836fcf/image.png" alt="">
이제 header branch에서 header 작업을 하면 변경 사항이 생길 것이다. 이것들을 저장하고(add), 변경 사항을 확정하고(commit), remote server에 올리고(push) remote server에서 팀원들이 변경사항을 보고 이를 main branch에 반영하는(PR) 일련의 과정을 거쳐야 한다. 기억이 새록새록...!!
...</p>
<hr>
<p><em>(2021)</em></p>
<h2 id="특정-branch-clone하기">특정 branch clone하기</h2>
<p>기존 <code>git clone {repository url}</code>을 하면 main 브랜치가 클론된다.
특정 브랜치에 작업 중인 요소를 클론하는 경우 
<code>git clone -b {branch name} {repository url}</code> 를 사용하면 된다.</p>
<hr>
<h2 id="remote-branch-가져오기">Remote branch 가져오기</h2>
<p><code>git remote update</code></p>
<hr>
<h2 id="npm-환경-통일">npm 환경 통일</h2>
<p><code>npm ci</code></p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[비동기 처리]]></title>
            <link>https://velog.io/@s-yeoyul/%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@s-yeoyul/%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Mon, 08 Nov 2021 09:35:36 GMT</pubDate>
            <description><![CDATA[<p>지금까지 프로젝트를 해오면서 어려웠던 것들이 많이 있었지만, 개인적으로 가장 난해했다고 느낀건 axios를 통한 비동기 처리였다. 많은 개념을 너무 급하게 배워서 그런걸 지도 모르겠다. 
이번 기회에 제대로 한번 익혀보자~!</p>
<p><a href="https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html">공식문서(Eng)</a></p>
<hr>
<h1 id="비동기-처리와-promise">비동기 처리와 Promise</h1>
<h2 id="비동기-처리">비동기 처리</h2>
<p>비동기 처리 방식(Aysnchronous Rendering)의 코드는 전체 코드가 <strong>순차적으로</strong> 실행되는 동기 방식(Synchronous Rendering)과 다르게 다른 코드들과 <strong>동기화 되어 있지 않다</strong>.
즉 렌더링을 하는 동시에 실행되어 일정 시간이 지난 후 개별적으로 끝난다.
<img src="https://i.imgur.com/hh3Mawr.png" alt="동기 처리와 비동기 처리 비교">
<a href="https://learnjs.vlpt.us/async/">출처 : 벨로퍼트 모던 자바스크립트</a>
그림으로도 이해가 어렵다면, 직접 코드를 보자. 그림의 1~3번을 코드로 표현해 보았다.</p>
<pre><code class="language-js">// 동기 처리 방식
console.log(&#39;Hello!&#39;); // 1

console.log(&#39;Bye!&#39;); // 2

console.log(&#39;Hello Again!&#39;); // 3

// Console
&gt;&gt; Hello!
&gt;&gt; Bye!
&gt;&gt; Hello Again!
</code></pre>
<p>위 코드에 대표적인 비동기 함수 setTimeout(callback, time)을 입혀보자. 
지정된 시간이 지나면 콜백 함수를 호출하는 방식이다.
(콜백 함수는 어떤 함수의 인자로 호출되는 함수를 의미한다.)</p>
<pre><code class="language-js">console.log(&#39;Hello!&#39;); // 1

setTimeout(() =&gt; console.log(&#39;Bye!&#39;), 3000); // 2

console.log(&#39;Hello Again!&#39;); // 3

// Console
&gt;&gt; Hello!
&gt;&gt; Hello Again!
// 3초 후
&gt;&gt; Bye!</code></pre>
<p>동기 처리와는 다르게 Bye!가 3초 후에 콘솔 창에 출력이 되는 모습을 확인할 수 있다. 
즉 다른 코드들과 동기화 되어 있지 않고 개별적으로 동작한다. 
따라서 다른 코드들이 동작하고 있을 때 비동기 처리를 이용하여 함께 실행되게 할 수 있다.
이러한 장점 때문에 비동기 처리를 주요 사용하는 경우가 여러 개 있다.</p>
<ul>
<li>Ajax Web API 요청: 서버에서 데이터를 받아야 할 때, 요청을 하고 서버에서 응답을 할 때 까지 기다려야 하기 때문에 비동기 처리를 이용한다.</li>
<li>파일 읽기: 주로 서버 쪽에서 파일을 읽어야 하는 상황에는 비동기적으로 처리한다.</li>
<li>암호화/복호화: 암호화/복호화를 할 때에도 바로 처리가 되지 않고, 시간이 어느정도 걸리는 경우가 있기 때문에 비동기적으로 처리한다.</li>
<li>작업 예약: 단순히 어떤 작업을 몇초 후에 스케쥴링 해야 하는 상황에는, setTimeout 을 사용하여 비동기적으로 처리한다.</li>
</ul>
<p>그러나 콜백 함수와 비동기 처리만 이용하는 경우 발생하는 문제점이 존재하는데... 
비동기 함수를 연쇄적으로 실행하고 추가적으로 출력 값 및 에러 처리를 해야 하는 경우이다.
이해를 돕기 위해 아래 코드를 보자.</p>
<pre><code class="language-js">// asynchronous function
const increaseAndPrint = (n, callback) =&gt; {
  setTimeout(() =&gt; {
    const increased = n + 1; // increase n
    console.log(increased); // print
    if (callback) {
      callback(increased); // run callback if condition is true
    }
  }, 1000);
};

increaseAndPrint(0, n =&gt; {
  increaseAndPrint(n, n =&gt; {
    increaseAndPrint(n, n =&gt; {
      increaseAndPrint(n, n =&gt; {
        increaseAndPrint(n, n =&gt; {
          console.log(&#39;끝!&#39;);
        });
      });
    });
  });
}); // 1. callback</code></pre>
<p>코드를 보면 알겠지만 비동기 처리를 하는 부분의 가독성이 처참한 수준이다.
이런 코드를 콜백 지옥이라고 부르고, 이러한 문제를 해결하기 위해 ES6에 <strong>Promise</strong>라는 기능이 도입된다.
이러한 콜백 지옥 코드에 Promise를 이용하고, async/await를 입히며 얼마나 깔끔해지는지에 집중해보자.</p>
<hr>
<h2 id="promise">Promise</h2>
<blockquote>
<p>The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value. 
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">MDN</a></p>
</blockquote>
<p>Promise는 말 그대로 약속이다. 기본적으로 <strong>미래</strong>에 실행될 함수에 대한 내용을 담고 있으며, 3가지 상태가 존재한다.</p>
<blockquote>
<p>A Promise is in one of these states:</p>
</blockquote>
<ul>
<li><strong>Pending</strong>: Initial state, neither fulfilled nor rejected.</li>
<li><strong>Fulfilled</strong>: Meaning that the operation was completed successfully.</li>
<li><strong>Rejected</strong>: Meaning that the operation failed.
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">MDN</a></li>
</ul>
<p><img src="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/promises.png" alt="Promise cycle">
먼저 새로운 Promise가 선언되면 pending(대기) 상태가 되며, 값을 가진 fulfilled(이행) 상태가 되거나 에러를 가진 rejected(실패) 상태가 될 수 있다.
콜백 함수의 인자로 resolve와 reject를 받으며, 성공시 resolve를, 실패시 reject를 실행한다.</p>
<pre><code class="language-js">const myPromise = new Promise((resolve, reject) =&gt; {
  resolve();
  // or reject();
  }); </code></pre>
<p>선언 후 대기 상태가 되고, resolve나 reject를 실행하면 이행 상태나 실패 상태가 된다.
그러나 Promise를 사용하는 목적은 이후에 있다. 연쇄적으로 Promise를 사용해야 하는 경우 어떻게 해야 할까??</p>
<blockquote>
<p>The methods promise.then(), promise.catch(), and promise.finally() are used to associate further action with a promise that becomes settled.</p>
</blockquote>
<p>바로 then함수와 catch함수를 이용하는 것이다.
then함수는 promise가 <strong>fufilled(이행) 상태</strong>인 경우 접근 가능하고 <strong>resolve된 값을 result로 받아온다.</strong>
catch함수는 promise가 <strong>rejected(실패) 상태</strong>일 때 접근 가능하며 <strong>reject에서 발생한 에러를 받아온다.</strong></p>
<pre><code class="language-js">const myPromise = new Promise((resolve, reject) =&gt; {
  resolve();
  // or reject();
  });
...
myPromise
  .then(res =&gt; console.log(res)) // 성공시 출력
  .catch(e =&gt; console.log(e)); // 실패시 출력</code></pre>
<p>연쇄적으로 사용해야 하는 경우에는</p>
<pre><code class="language-js">const increase = (number) =&gt; {
  const myPromise = new Promise((resolve, reject) =&gt; {
   setTimeout(() =&gt; {
     const result = number + 10;
     if (result &gt; 50) {
       const e = new Error(&quot;NumberBigError&quot;);
       return reject(e); // 실패시 reject 함수를 실행, rejected
     }
     resolve(result); // 성공시 resolve 함수를 실행, fufilled
   }, 3000);
  });
  return myPromise; // promise를 리턴
}


increase(0)
  .then(result =&gt; increase(result))
  .then(result =&gt; increase(result))
  .then(result =&gt; increase(result))
  .then(result =&gt; increase(result))
  .then(result =&gt; increase(result))
  .catch(error =&gt; console.log(error)); // 2. promise</code></pre>
<p>위와 같이 작성한다. 콜백 함수만을 이용했을 때와 비교했을 때 가독성을 비교해보자.</p>
<hr>
<h2 id="asyncawait">async/await</h2>
<p>Promise를 더욱 쉽게 사용할 수 있게 해주는 문법으로 ES2017에 도입되었다.</p>
<blockquote>
<p><strong>Async</strong> functions can contain <strong>zero or more await expressions.</strong>
<strong>Await expressions</strong> make <strong>promise-returning functions</strong> behave as though they&#39;re synchronous by suspending execution until the returned promise is fulfilled or rejected.
<strong>The resolved value of the promise</strong> is treated as the <strong>return value of the await expression.</strong>
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">MDN</a></p>
</blockquote>
<p>비동기 처리를 사용할 함수의 앞에 async 접두어를 붙이고, HTTP와 통신하여 비동기 처리를 하는 함수 앞에 await을 붙인다. await이 붙은 함수는 반드시 Promise 객체를 리턴해야 된다.</p>
<p>위 코드에서 <code>increase(0).then()...</code> 부분을 async/await을 이용해 다시 쓰면</p>
<pre><code class="language-js">async function runTasks() {
  try {
    let result = await increase(0);
    result = await increase(result); // 10
    result = await increase(result); // 20
    result = await increase(result); // 30
    result = await increase(result); // 40
    result = await increase(result); // 50
  }
  catch (e) {
    console.log(e);
  }
} // 3. promise + async/await</code></pre>
<p>더욱 편하게 다룰 수 있다. 에러처리는 <code>catch()</code>대신 <code>try...catch...</code> 구문을 이용한다. </p>
<h2 id="references">References</h2>
<p>MDN Promise 문서 : <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise</a>
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function</a>
벨로퍼트 Promise 강의 : <a href="https://learnjs.vlpt.us/async/01-promise.html">https://learnjs.vlpt.us/async/01-promise.html</a>
캡틴판교 Promise 강의 : <a href="https://joshua1988.github.io/web-development/javascript/promise-for-beginners/">https://joshua1988.github.io/web-development/javascript/promise-for-beginners/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Pagination; 페이지네이션]]></title>
            <link>https://velog.io/@s-yeoyul/Pagination-%ED%8E%98%EC%9D%B4%EC%A7%80%EB%84%A4%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@s-yeoyul/Pagination-%ED%8E%98%EC%9D%B4%EC%A7%80%EB%84%A4%EC%9D%B4%EC%85%98</guid>
            <pubDate>Thu, 04 Nov 2021 12:10:10 GMT</pubDate>
            <description><![CDATA[<p>전 세계 어느 사이트를 가던, 사용자에게 최적의 경험을 제공하기 위해 필요한 기능이 있다.
바로 페이지네이션(Pagination)이다.
이름에서 알 수 있듯이 페이지네이션은 사용자가 데이터를 보기 편하게 한 화면에 정해진 양의 데이터를 보여주는 기능을 말한다.
<img src="https://imyeonn.github.io/assets/images/post/002/142_00title.png" alt="예시">
어느 사이트를 가던 위 그림과 같이 정보를 분할해놓는 구조를 다들 본적이 있을 것이다. 
같은 기능이지만 사용자가 더 쉽고 편하게 정보에 접근할 수 있게 구현된 방법으로 Infinite scrolling이 있다.
<img src="https://miro.medium.com/max/700/1*0byA6lpPKSoTLOoK4EWruA.gif" alt="예시">
페이스북이나 인스타그램, 유튜브, 핀터레스트 등 많은 사이트가 위의 방식을 사용하고 있다.
페이지네이션 기능을 구현하기 위해서는 백엔드와 프론트엔드에서 모두 작업해야 하며, 프론트엔드는 백엔드에 <strong>표시할 데이터의 위치</strong>와 <strong>표시할 데이터의 개수</strong>를 요청해야 하며 백엔드에서는 요청에 맞는 데이터를 응답한다. 페이지네이션을 어떻게 구현하는지에 따라서 현재 데이터의 위치를 표현하는 방법이 다르다.</p>
<blockquote>
<ol>
<li>Offset-based
오프셋: 표시할 데이터 위치(=몇 번째 페이지인지), Limit: 표시할 최대 데이터 개수 </li>
<li>Cursor-based
커서: 첫번째로 표시할 데이터의 위치(=현재 커서 위치), Limit: 표시할 최대 데이터 개수</li>
</ol>
</blockquote>
<p>이번 프로젝트에서 사용한 방법은 오프셋 기반 Infinite scrolling이다. 
<a href="https://www.youtube.com/watch?v=NZKUirTtxcg">유튜브 영상</a>을 참고하여 많은 도움이 되었다. </p>
<p>Ref라는 개념을 처음 다루게 되는데, Ref는 DOM을 직접 조작하는데 사용된다</p>
<ol>
<li>특정 input에 포커스 주기</li>
<li><strong>스크롤 박스 조작하기</strong></li>
<li>Canvas 요소에 그림그리기
등등...
이번 프로젝트에서는 2번, 스크롤 조작을 Ref를 통해 관리하게 된다.</li>
</ol>
<pre><code class="language-js">function App() {
  const [query, setQuery] = useState(&quot;&quot;);
  const [pageNum, setPageNum] = useState(1);
  const { loading, error, list, hasMore } = useSearchBook(query, pageNum);

  const observer = useRef(); 
  const lastBookElementRef = useCallback( 
    (node) =&gt; {
      if (isLoading) return;
      if (observer.current) observer.current.disconnect();
      observer.current = new IntersectionObserver((entries) =&gt; {
        if (entries[0].isIntersecting &amp;&amp; hasMore) { // 마지막 요소가 보이고 더 로딩할 페이지가 존재하면 
          setPageNum((prev) =&gt; prev + 1); // 다음 페이지를 불러온다
        }
      });
      if (node) observer.current.observe(node);
    },
    [loading, hasMore]
  );

  const handleChange = (e) =&gt; {
    setQuery(e.target.value);
    setPageNum(1);
  };

  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;h1&gt;Infinite Scroll&lt;/h1&gt;
      &lt;input type=&quot;text&quot; onChange={handleChange} value={query} /&gt;
      {list.map((item, i) =&gt; {
        const isLastElement = books.length === i + 1;
        isLastElement ? (
          &lt;div key={i} ref={lastBookElementRef}&gt; 
          {book}
          &lt;/div&gt;
        ) : (
        &lt;div key={i}&gt;{book}&lt;/div&gt;
        )
      })}
      &lt;div&gt;{isLoading &amp;&amp; &quot;Loading...&quot;}&lt;/div&gt;
      &lt;div&gt;{error &amp;&amp; &quot;Error...&quot;}&lt;/div&gt;
    &lt;/div&gt;
  );

export default App;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Routing]]></title>
            <link>https://velog.io/@s-yeoyul/Routing</link>
            <guid>https://velog.io/@s-yeoyul/Routing</guid>
            <pubDate>Tue, 02 Nov 2021 08:37:58 GMT</pubDate>
            <description><![CDATA[<p>프로젝트를 하면서 새로운 내용을 배우면 바로바로 정리해놓는게 좋더라.
오늘은 urlQuery를 쓸 일이 생겨서, 이것에 대해 알아보자.</p>
<h2 id="1-url">1. url</h2>
<p><img src="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_is_a_URL/mdn-url-all.png" alt="img">
우리가 흔히 보는 url의 구조이다. <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_is_a_URL">MDN참조</a>
react-router 라이브러리를 이용하면 라우팅이 가능해진다.</p>
<pre><code class="language-js">import React from &#39;react&#39;;
import { BrowserRouter, Switch, Route } from &#39;react-router-dom&#39;;
import Home from &#39;components/Home&#39;;

const App = () =&gt; {
  const id = 1;
  return (
    &lt;BrowserRouter&gt;
      &lt;Switch&gt;
        &lt;Route path=&#39;/student/:id&#39; component={Home} /&gt;
      &lt;/Switch&gt;
    &lt;/BrowserRouter&gt;
  );
};</code></pre>
<p>App.js에서 <code>~/student/1</code>로 라우팅한다.
이때 Home 컴포넌트는 기본적으로 history객체를 props로 받게된다.
그리고 함수형 컴포넌트에서는 useHistory객체를 이용하여 history 객체에 접근 가능하며,
push/goBack/replace/block 등의 함수를 이용하여 직접적으로 라우팅할 수 있다.</p>
<pre><code class="language-js">.catch((e) =&gt; {
        toast.error(e.message);
        history.push(&quot;/students&quot;);
      });</code></pre>
<h2 id="2-parameter">2. parameter?</h2>
<p>url에 변수를 표현하는 방법은 2가지가 있다.
이번에 알아볼 urlQuery와 urlParams가 존재한다.</p>
<p>먼저 urlParams는 부모 컴포넌트로 부터 match 정보를 받아온다. 
match.params로 접근한 객체에는 현재 url이 Route 컴포넌트에서 임의로 정한 규칙과 어떻게 일치하는지에 대한 정보가 들어있다. <strong>보통 urlParams는 id나 userName 같은 정적인 변수를 받아오는데 사용된다.</strong></p>
<p><code>&lt;Route path=&quot;/.../:parameters component={Page}&quot;</code> 
Page 컴포넌트에서 props를 받고, match.params.parameters로 url의 변수에 접근 가능하다.
함수형 컴포넌트에서는 useParams라는 Hook을 이용하면 더욱 쉽게 url에 접근이 가능하다.</p>
<pre><code class="language-js">const { id, userName } = useParams();</code></pre>
<p>이제 urlQuery를 보자.
Query는 라우터로부터 전달되는 props 개체의 location에 존재하는 search 값으로부터 받아올 수 있으며, <strong>주로 검색 기능이나 페이지에 특정 옵션을 걸 때 사용한다.</strong></p>
<pre><code class="language-js">{
  key: &#39;ac3df4&#39;, // not with HashHistory!
  pathname: &#39;/somewhere&#39;
  search: &#39;?some=search-string&#39;,
  hash: &#39;#howdy&#39;,
  state: {
    [userDefined]: true
  }
}</code></pre>
<p>함수형 컴포넌트에서는 useLocation을 통해 위 코드와 같은 location 객체에 접근할 수 있다. 우리가 분석하고자 하는 query-string은 search 값에 존재하며, ?A=B&amp;C=D...의 구조로 params 보단 다소 복잡하게 되어 있다. 
이 문자열을 파싱하여 분석하기 위한 라이브러리로 query-string(qs)나 URLSearchParams가 있는데, 여기서는 URLSearchParams를 이용해 보자. <a href="https://developer.mozilla.org/ko/docs/Web/API/URLSearchParams">MDN</a>
useLocation Hook을 이용하면 더욱 쉽게 다룰 수 있다.</p>
<pre><code class="language-js">
const { search } = useLocation(); // search ===&quot;q=URLUtils.searchParams&amp;topic=api&quot;
// 맨 앞의 ?는 제거된 채로 인식됨
var searchParams = new URLSearchParams(paramsString);

//Iterate the search parameters.
for (let p of searchParams) {
  console.log(p);
}

searchParams.has(&quot;topic&quot;) === true; // true
searchParams.get(&quot;topic&quot;) === &quot;api&quot;; // true
searchParams.getAll(&quot;topic&quot;); // [&quot;api&quot;]
searchParams.get(&quot;foo&quot;) === null; // true
searchParams.append(&quot;topic&quot;, &quot;webdev&quot;);
searchParams.toString(); // &quot;q=URLUtils.searchParams&amp;topic=api&amp;topic=webdev&quot;
searchParams.set(&quot;topic&quot;, &quot;More webdev&quot;);
searchParams.toString(); // &quot;q=URLUtils.searchParams&amp;topic=More+webdev&quot;
searchParams.delete(&quot;topic&quot;);
searchParams.toString(); // &quot;q=URLUtils.searchParams&quot;</code></pre>
<p>이번 프로젝트에서 사용한 방식은</p>
<ol>
<li>검색 버튼을 누르면 history.push를 이용해 /...?A=B&amp;C=D로 보내고</li>
<li>location객체에서 search값을 받아오고</li>
<li>적당한 파싱 라이브러리를 이용하여 key값과 value값을 관리하고
의 순서대로 진행되었다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 반응형 웹 만들기]]></title>
            <link>https://velog.io/@s-yeoyul/React-%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@s-yeoyul/React-%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Fri, 15 Oct 2021 03:20:31 GMT</pubDate>
            <description><![CDATA[<h2 id="motivation">Motivation</h2>
<p>사실 디자인에 평소에 관심이 많았다. 조예가 깊다는 말이 아니고 그냥 막연히 배워보고 싶다, 디자인이 잘 된 사이트를 보면 멋지다 이정도..? CSS를 알게 되고 이런걸 내가 할 수 있구나, 직접 디자인 해봐야지 라고 마음 먹었는데 막상 하려니 참 막막했다. 뭔가 각잡고 하면 할 수 있을 거 같은데 막상 하려니 또 귀찮고 해서 그냥 볼 수 있을 정도로만 구현해야지 하면서 여태까지 손을 놓고 있었는데, 휴학도 했고 아직 시간도 많으니 깔끔하게 한번 만들어 보려고 글을 쓴다! 역시 이렇게 기록을 해두어야 의지도 생기고 대충하지도 않고 좋은 것 같다. 대학와서는 만사가 다 귀찮아서 이렇게 생산적인 행위(?)를 일절 안했는데 다시 시작해보자.</p>
<h2 id="잘-반응해야-보기-편하다">잘 반응해야 보기 편하다</h2>
<p>지금까지 만든 사이트의 문제는 너무 정적이라는 것이다.. 사실 chrome에만 최적화시켜 놓아서 다른 플랫폼에서 보게되면 가관이 따로 없다. 유저가 보는 화면에 따라서 적절하게 반응하여(responsive) 보여주는 방법이 필요했다.
react-responsive 라이브러리를 이용하면 유저가 사용하는 디바이스에 대응하여 알맞는 화면을 제공할 수 있다. <a href="https://www.npmjs.com/package/react-responsive">공식 문서</a>에 나와있는 훌륭한 예시를 소개한다.</p>
<pre><code class="language-javascript">import { useMediaQuery } from &#39;react-responsive&#39;

const Desktop = ({ children }) =&gt; {
  const isDesktop = useMediaQuery({ minWidth: 992 })
  return isDesktop ? children : null
}
const Tablet = ({ children }) =&gt; {
  const isTablet = useMediaQuery({ minWidth: 768, maxWidth: 991 })
  return isTablet ? children : null
}
const Mobile = ({ children }) =&gt; {
  const isMobile = useMediaQuery({ maxWidth: 767 })
  return isMobile ? children : null
}
const Default = ({ children }) =&gt; {
  const isNotMobile = useMediaQuery({ minWidth: 768 })
  return isNotMobile ? children : null
}

const Example = () =&gt; (
  &lt;div&gt;
    &lt;Desktop&gt;Desktop or laptop&lt;/Desktop&gt;
    &lt;Tablet&gt;Tablet&lt;/Tablet&gt;
    &lt;Mobile&gt;Mobile&lt;/Mobile&gt;
    &lt;Default&gt;Not mobile (desktop or laptop or tablet)&lt;/Default&gt;
  &lt;/div&gt;
)

export default Example</code></pre>
<p>조건문 형식으로 삼항 연산자와 null을 이용하여 화면의 minWidth값에 대응되는 component가 보여지게 된다. 그러나 width값에 따라서 다른 컴포넌트를 return하는 것 보다, 정렬 방식을 바꾸는 방법은 없을까?</p>
<h3 id="media-query">media query</h3>
<p>구글링을 하다가 적절한 방법을 찾았다. media query를 이용하여 max-width를 설정해놓고, flex-direction을 row와 column으로 바꾸면 아주 좋을 것 같다! 해보자! </p>
<details>
<summary>
    CSS 기본
</summary>

<p>  프론트엔드 특징이 어거지로 만들어도 결과가 어찌저찌 나오기 때문에 디버깅이 힘든 경우가 많은
  데.. 처음부터 사이트를 너무 정적으로 만들어서 이건 뭐 처음부터 다 뜯어 고쳐야 하는 수준이다.. 명령어 제대로 알지도 못하고 결과만 보고 달리면 이렇게 된다 ㅜㅜㅜ 이제라도 하나씩 정리해야겠다</p>
<ul>
<li>가장 기본적인 속성 margin, padding은 border를 기준으로 각각 바깥 여백, 안쪽 여백을 의미한다.
<img src="https://blog.kakaocdn.net/dn/Ap2tP/btqOjnFSRjH/L4QqUFVtkrGJ4jWRX9WbJK/img.png" alt="M-B-P"><pre><code class="language-css">example {
padding: 4px;
padding: 4px 8px; // clockwise
}</code></pre>
</li>
<li>display 속성<ol>
<li>inline(default)
height, width 속성을 지정할 수 없다.(=Inline element) 한 줄에 이어서 쓴다.
ex) span, a</li>
<li>block
자동으로 줄바꿈을 하여 하나의 행을 차지하고, width 등의 속성을 지정할 수 있다.
ex) div, p, h1</li>
<li>inline-block
기본적으로 inline 속성을 가지나 width 등의 속성을 지정할 수 있다,
ex) input, button, select</li>
<li>flex
레이아웃 배치 툴이다. 내용이 방대하므로 [이 사이트]
(<a href="https://studiomeal.com/archives/197)%EB%A5%BC">https://studiomeal.com/archives/197)를</a> 참조하자. 
justify는 가로 정렬, align은 세로 정렬이라는 것을 명심하자. flex-direction을 이용하
여 반응형 웹을 구현할 것이다.</li>
<li>grid
마찬가지로 레이아웃 배치 툴이며, <a href="https://studiomeal.com/archives/533">이 사이트</a>에 잘 정리되어 있다.</li>
</ol>
</li>
<li>position 속성<ol>
<li>static(default)
요소를 일반적인 흐름에 맞게 배치하고, top/left/z-index 등의 속성을 사용할 수 없다. 일
반적인 흐름이란 요소들의 기본적인 display 속성을 고려하여 배치한다는 뜻이다.</li>
<li>relative
요소를 일반적인 흐름에 맞게 배치하고, <strong>배치된 위치를 기준으로 상대적으로</strong> top, left 등
의 속성을 적용할 수 있다.</li>
<li>absolute
일반적인 흐름이 아닌 <strong>가장 가까운 부모 컴포넌트를 기준으로</strong> 배치하며 top, left 등의 속
성을 적용할 수 있다.</li>
<li>fixed
일반적인 흐름이 아닌 <strong>Viewport를 기준으로</strong> 배치하며, 이는 곧 사용자가 보는 화면 상에
고정되어 있음을 의미한다.</details>

</li>
</ol>
</li>
</ul>
<p><a href="https://inpa.tistory.com/entry/CSS-%F0%9F%95%B9%EF%B8%8F-%EC%88%98%ED%8F%89-%EC%88%98%EC%A7%81-%EA%B0%80%EB%A1%9C-%EC%84%B8%EB%A1%9C-%EC%A0%95%EB%A0%AC-%EA%B8%B0%EB%B2%95-%F0%9F%92%AF-%EB%AA%A8%EC%9D%8C-%EC%A0%95%EB%A6%AC#">CSS 정렬에 관한 좋은 글</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[초심]]></title>
            <link>https://velog.io/@s-yeoyul/%EC%B4%88%EC%8B%AC</link>
            <guid>https://velog.io/@s-yeoyul/%EC%B4%88%EC%8B%AC</guid>
            <pubDate>Wed, 13 Oct 2021 07:44:11 GMT</pubDate>
            <description><![CDATA[<h1 id="frontend-developer">Frontend Developer</h1>
<h2 id="0">0.</h2>
<p>세상에 널린게 직업인데, 거기서 개발자를 고르고, 또 프론트엔드를 고른 이유는 무엇일까.
사실 언젠가 부터 컴퓨터를 이용하는 직업을 하고 싶었다. 요즘 세상에 컴퓨터를 쓰지 않는 직업이 몇이나 되겠냐만은.. 
돌이켜보면 초등학교 때 인것 같다. 초 5때였나, 하마치를 이용해 직접 마인크래프트 서버를 열어서 친구들이랑 같이 했던 기억이 있다. 지금에서야 별거 아니지만, 당시엔 32비트 64비트 따져가며 버킷을 다운받고 C드라이브 깊숙한 곳을 탐험하고 하는게 참 신기했다. 하나의 다른 세상이었다. 그 시절 우리가 가장 자유롭게 사용할 수 있는 공간이었다. 
아무튼 막연히 컴퓨터 컴퓨터 하다가, 고등학교때 아두이노 프로젝트를 하면서 이 분야가 정말 마음에 들었다. 막상 대학에 들어오니 PS스러운 것만 잔뜩 시키고 웹/앱 개발은 알려주지 않더라. 
그래서 또 어떻게 배울 방법을 모색하다 보니 여기까지 왔다. 프론트엔드? 내가 개발한 것을 가시적으로 볼 수 있다는 것이 가장 마음에 들었다. 막연히 홈페이지를 만들어보고 싶다는 생각을 하기도 했고. 그냥 일단 해보자 라는 마인드였고, 그렇게 약 한달여간을 html, css, javascript, 그리고 React와 보내게 되었다.</p>
<h2 id="1">1.</h2>
<p>인생은 참 어쩌다 보니 살게 되는 것 같다. 물결에 떠밀려 목적지에 도착하면 그 과정은 잘 기억나지 않는다. 그렇기에 과거를 그리워하나보다. 참 일기라도 몇개 써둘걸 그랬다.
그런 심정으로 끄적이는 중이다. 평소에 잘 쓰지도 않는 글을, 굳이 블로그까지 만들며 쓰는 이유는 그냥 스물하나의 나를 기억하고 싶어서.. 뭐 다른 것들은 부차적이다. 프로젝트 계획, 배운 내용 정리 등등
막상 만들고 보니 별 거 없는 것 같지만.. </p>
<h2 id="2">2.</h2>
<p>생각보다 사회는 나에게 많은 것을 해주지 않는다. 그걸 스물하나에 처음 깨닫다니. 
연못 위의 오리는 평온한 것처럼 보이지만 그 아래에선 끊임없이 발을 움직이고 있다. 
휴학을 결심했지만, 아무에게도 말 못하고 있다. 떳떳한 명분도 존재하고, 지금까지 열심히 달려왔다는 것을 부정하려는 사람도 없을 텐데.. 왜일까.<br>가장 큰 이유는 지쳐서. 너무 힘들었다. 낮게 기대면 의도치 않게 상대방을 짓누르고 높은데는 기대기는 커녕 우러러 볼수록 나를 좀먹는다. 결국 기댈 곳은 나밖에 없고, 그 조차 한계가 명확하다. 기댄다는 표현이 맞는지.. 그냥 흘러가는 대로 살게 되는 것이다. 
현상유지 하는 것도 버거운데, 3학기동안 방 안에 틀어박혀서 남들만큼 하고 따로 생산적인 일을 하는게 쉬운 일이 아니다. 이미 3년을 그렇게 살았는데, 그 결과가 이렇다니 과거의 나에게 너무 미안하지 않은가.. 눈물이 날 지경이다.
머릿속에 하고싶은 말이 많지만 정리가 되지 않는다. 항상 머릿속에 있는 말들을 끄집어 내면 어딘가 변질되더라. 그저 후회하지 않기만을 바래야 겠다.</p>
]]></description>
        </item>
    </channel>
</rss>