<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>lea-hwang.log</title>
        <link>https://velog.io/</link>
        <description>끊임없이 도전하는 개발자, 황희원입니다 :)</description>
        <lastBuildDate>Mon, 24 Apr 2023 05:09:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>lea-hwang.log</title>
            <url>https://images.velog.io/images/lea-hwang/profile/c079aa03-b81a-496e-a4c7-3d9980134550/셀카1.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. lea-hwang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/lea-hwang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[네트워크] 신입 개발자 면접 질문 정리]]></title>
            <link>https://velog.io/@lea-hwang/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8B%A0%EC%9E%85-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@lea-hwang/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8B%A0%EC%9E%85-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 24 Apr 2023 05:09:40 GMT</pubDate>
            <description><![CDATA[<h3 id="✅osi-7계층">✅OSI 7계층</h3>
<p>네트워크 프로토콜이 통신하는 구조를 7개의 계층으로 분리하여 각 계층간 상호 작동하는 방식을 정해 놓은 것을 말합니다.</p>
<p>제일 아래에서부터 물리 계층, 데이터링크 계층, 네트워크 계층, 전송 계층, 세션 계층, 표현 계층, 응용 계층이 있습니다.</p>
<p><strong>물리계층</strong>은 전기적, 기계적인 특성을 이용해 데이터를 전송하는 계층입니다. (케이블, 리피터, 허브)</p>
<p><strong>데이터링크 계층</strong>은 인접한 두 장치 간의 신뢰성있는 정보 전송(오류 파악, 재전송)을 담당하는 계층입니다. MAC 주소를 이용해 통신하며 프레임 단위로 데이터가 구성됩니다.(브리지, 스위치)</p>
<p><strong>네트워크 계층</strong>은 라우팅 기능을 맡고 있는 계층으로 목적지까지 안전하고 빠르게 데이터를 보낼 수 있도록 하는 계층입니다. IP 주소를 통해 어디로 데이터를 보내야 할지 판단하며, 패킷 단위로 데이터가 구성됩니다. (라우터, L3 스위치)</p>
<p><strong>전송 계층</strong>은 종단 간 신뢰성있고 정확한 데이터 전송을 담당하는 계층입니다. 오류 검출 및 복구, 흐름제어와 중복 검사를 통해 신뢰성있고 효율적인 데이터 전송을 꾀하며 Port 번호를 사용합니다. TCP와 UDP가 이 계층에 속하며 세그먼트/데이터그램 단위로 데이터가 구성됩니다.</p>
<p><strong>세션 계층</strong>은 통신 장치 간 상호작용 및 동기화를 제공합니다. 세션에서 에러발생시 복구를 관리합니다.</p>
<p><strong>표현 계층</strong>은 데이터를 어떻게 표현할 지 정하는 계층으로 암호화/복화화, 압축 등의 기능을 담당하고 있습니다.</p>
<p><strong>응용 계층</strong>은 사용자와 가장 밀접한 계층으로 인터페이스 역할을 합니다.</p>
<h3 id="✅tcpip-4계층">✅TCP/IP 4계층</h3>
<p>TCP/IP 프로토콜이 미 국방성 통신 표준으로 채택되면서, 해당 프로토콜의 통신 과정을 크게 4개의 계층 구조로 나눠 설명한 것을 말합니다.</p>
<p>네트워크 접근 계층, 인터넷 계층, 트랜스포트 계층, 어플리케이션 계층 의 총 4계층으로 구성됩니다.</p>
<p><strong>네트워크 접근 계층</strong>은 물리적으로 데이터가 네트워크를 통해 어떻게 전송되는지를 정의합니다. 물리적인 주소로 <code>MAC</code>을 사용하며 에러검출 및 패킷의 프레임화를 담당합니다. (Ethernet, Token Ring)</p>
<p><strong>인터넷 계층</strong>이란 통신 노드 간의 IP 패킷을 전송하는 기능과 라우팅 기능을 담당합니다. 대표적인 프로토콜로 IP가 있으며, IP 주소를 기반으로 데이터를 주고 받습니다.</p>
<p><strong>전송 계층</strong>은 통신 노드 간의 연결을 제어하고 신뢰성있는 데이터 전송을 담당합니다. TCP, UDP가 여기에 속하며 포트 번호를 이용해 전송합니다.</p>
<p><strong>응용 계층</strong>은 사용자와 가장 가까운 계층으로 인터페이스 역할을 합니다. HTTP, FTP, SSH 등이 여기에 포함됩니다.</p>
<h3 id="✅tcp와-udp">✅TCP와 UDP</h3>
<p>TCP란 두 개의 호스트를 연결하고 신뢰성 있게 데이터를 전송해주는 프로토콜입니다. 데이터와 패킷이 순서대로, 에러, 분실, 중복 없이 전달될 수 있도록 합니다. 뿐만 아니라 흐름제어와 혼잡제어를 통해 데이터를 효율적으로 잘 받을 수 있도록 합니다.</p>
<p>UDP란 두 개의 호스트를 연결하지 않고 신뢰성있지 않게 데이터를 전송하는 프로토콜입니다. 데이터를 빠르게 전달할 수 있다는 장점이 있습니다.</p>
<h3 id="✅3-way-handshake--4-way-handshake">✅3-way handshake &amp; 4-way handshake</h3>
<p><code>3-way handshake</code>란 TCP 프로토콜에서 정확한 전송을 보장하기 위해 두 호스트의 연결을 성립하는 과정을 의미합니다.</p>
<ol>
<li>클라이언트가 서버에게 SYN 패킷을 보냄 (sequence : x)</li>
<li>서버가 SYN(x)을 받고, 클라이언트로 받았다는 신호인 ACK와 SYN 패킷을 보냄 (sequence : y, ACK : x + 1)</li>
<li>클라이언트는 서버의 응답은 ACK(x+1)와 SYN(y) 패킷을 받고, ACK(y+1)를 서버로 보냄 이렇게 3번의 통신이 완료되면 연결이 성립된다. (3번이라 3 way-handshake인 것)</li>
</ol>
<p><code>4-way handshake</code>란 TCP 프로토콜에서 연결을 해제하기 위한 과정입니다. </p>
<ol>
<li>클라이언트는 서버에게 연결을 종료한다는 FIN 플래그를 보낸다.</li>
<li>서버는 FIN을 받고, 확인했다는 ACK를 클라이언트에게 보낸다. (이때 모든 데이터를 보내기 위해 CLOSE_WAIT 상태가 된다)</li>
<li>데이터를 모두 보냈다면, 연결이 종료되었다는 FIN 플래그를 클라이언트에게 보낸다.</li>
<li>클라이언트는 FIN을 받고, 확인했다는 ACK를 서버에게 보낸다. (아직 서버로부터 받지 못한 데이터가 있을 수 있으므로 TIME_WAIT을 통해 기다린다.) - 서버는 ACK를 받은 이후 소켓을 닫는다 (Closed) - TIME_WAIT 시간이 끝나면 클라이언트도 닫는다 (Closed) 이렇게 4번의 통신이 완료되면 연결이 해제된다.</li>
</ol>
<h3 id="✅http--https">✅HTTP &amp; HTTPS</h3>
<p><strong>HTTP</strong>란 인터넷 상에서 클라이언트와 서버가 자원을 주고 받을 때 사용하는 통신 규약입니다. HTTP는 누군가 네트워크에서 신호를 가로채면 내용이 노출되는 보안이슈가 발생할 수 있는데 이를 보완한 것이 HTTPS입니다. </p>
<p><strong>HTTPS</strong>란 인터넷 상에서 정보를 암호화하는 SSL 프로토콜을 사용해 클라이언트와 서버가 자원을 주고 받을 때 쓰는 통신 규약으로 공개키 암호화 방식을 사용합니다. </p>
<h3 id="✅http1-vs-http2">✅HTTP1 vs HTTP2</h3>
<p>HTTP1.1은 1999년 출시 이후 지금까지 가장 많이 사용되고 있습니다. HTTP는 웹상에서 클라이언트와 웹서버간 통신을 위한 프로토콜 중 하나입니다. HTTP1.1은 기본적으로 연결당 하나의 요청과 응답을 처리하기 때문에 동시전송 문제와 다수의 리소스를 처리하기에 속도와 성능 이슈를 가지고 있습니다.</p>
<p>이렇다 보니, HOL(Head Of Line) Blocking-특정응답지연, RTT(Round Trip TIme) 증가, 헤비한 Header구조라는 문제점들을 가지고 있습니다. 이러한 문제점들을 해결하기 위해, UI 개발자/프론트엔드개발자는 이미지 스프라이트, 도메인샤딩, CSS/JavaScript 압축, Data URI 등을 업무에 사용하였습니다.</p>
<p>그렇게 고군분투 하던 중, HTTP2가 세상에 소개되었습니다. HTTP2는 성능 뿐만 아니라 속도면에서도 월등한 녀석입니다. Multiplexed Streams(한 커넥션에 여러개의 메세지를 동시에 주고 받을 수 있음), Stream Prioritization(요청 리소스간 의존관계를 설정), Server Push(HTML문서상에 필요한 리소스를 클라이언트 요청없이 보내줄 수 있음), Header Compression(Header 정보를 HPACK압충방식을 이용하여 압축전송)을 사용하여 선을을 획기적으로 향상 시켰습니다</p>
<h3 id="✅쿠키와-세션의-차이">✅쿠키와 세션의 차이</h3>
<p>쿠키와 세션은 HTTP의 특성인 <strong>비연결성</strong>(<code>connectionless</code>), <strong>비상태성</strong>(<code>stateless</code>) 때문에 사용하게 됩니다.</p>
<blockquote>
<p><strong>비연결성</strong>: 요청을 보내고 난 뒤 응답을 받고 연결이 끊어지는 것을 의미</p>
<p><strong>비상태성</strong>: 커넥션을 끊는 순간 상태정보를 유지하지 않는 것을 의미</p>
</blockquote>
<p>그러나, 로그인이나 장바구니 같은 기능을 구현하기 위해선 상태 정보를 유지할 필요가 있는데요. 이런 stateful한 상황을 대처하기 위해 쿠키와 세션을 사용합니다.</p>
<p><strong>쿠키</strong>는 서버에서 만들어 클라이언트에 넘긴 작은 정보파일입니다. 클라이언트 측에서 특정 이벤트를 수행하며 쿠키를 수정할 수 있고 이를 다시 서버에 요청과 함께 넘겨 특정 데이터를 요청할 수 있습니다. <u>쿠키는 브라우저가 종료돼도 삭제되지 않습니다</u>.</p>
<p>그러나 이 <u>쿠키는 서버가 가지고 있는 것이 아니기 때문에 임의로 고치거나 가로챌 수 있어 보안에 취약</u>합니다.</p>
<blockquote>
<p><code>httponly cookie</code>: document.cookie로 접근 불가능 (XSS 공격 대비)</p>
<p><code>secure cookie</code>: https 프로토콜 상에서 암호화된 요청일 경우에만 요청되는 쿠키</p>
</blockquote>
<p><strong>세션</strong>은 방문자가 웹 서버에 접속해 있는 상태를 하나의 단위로 보는 것을 의미합니다.  사용자가 접속할 경우 서버에서는 세션을 만들어 session_id를 발급하고 클라이언트 측에서는 해당 sid를 쿠키에 저장합니다. 그래서 서버에 요청할 때마다 해당 쿠키를 전달하는 방식으로 동작합니다. <u>세션은 브라우저가 종료되면 만료 기간에 상관없이 삭제되며 sid로 사용자를 구분하기 때문에 보안 측면에서 그냥 쿠키 만을 사용했을 때 보다 안전합니다.</u></p>
<h3 id="✅cors">✅CORS</h3>
<p>CORS란 <u>서로 다른 Origin 간에 자원을 공유하는 것</u>을 의미합니다. 여기서 Origin이란, Protocol, Host, Port를 모두 합친 것을 의미합니다. 기본적으로 Origin이 서로 같을 때만 자원을 공유할 수 있습니다. 이를 SOP라 부릅니다. 그런데, 서버와 클라이언트의 요청처럼 서로 다른 Origin 간의 데이터를 공유할 필요가 있는 경우가 있습니다. 이렇게 SOP의 예외사항을 둘 것이 CORS라고 할 수 있습니다. CORS에 대한 설정은<code>Access-Control-Allow-Origin</code> 의 값에 자원을 공유할 다른 Origin의 정보를 담으면 됩니다.</p>
<h3 id="✅rest-api">✅REST API</h3>
<p>REST API란, <u>자원의 이름으로 해당 자원의 상태를 주고 받는 것</u>을 의미합니다. <strong>HTTP URI</strong>를 통해 자원을 명시하고 <strong>HTTP Method</strong>를 통해 해당 자원에 대한 CRUD operation을 적용할 수 있으며 서버는 요청에 대한 응답으로 JSON, XML과 같은 <strong>HTTP Method Payload</strong>를 받을 수 있습니다.</p>
<h3 id="✅웹-브라우저에-wwwnavercom을-입력하면-일어나는-일">✅웹 브라우저에 <a href="http://www.naver.com%EC%9D%84">www.naver.com을</a> 입력하면 일어나는 일</h3>
<ol>
<li>주소창에 <a href="http://www.naver.com%EC%9D%84">www.naver.com을</a> 입력한다.<ul>
<li>protocol, domain, path 등의 형식으로 입력되면 브라우저가 해당 도메인 네임에 대한 IP 주소를 요청한다. </li>
<li>protocol을 따로 명시하지 않는다면 기본적으로 <code>https</code>로 요청한다.</li>
</ul>
</li>
<li>DNS 서버에 도메인 네임을 전달하여 IP 주소를 받아온다.</li>
<li>가져온 IP 주소를 토대로 서버에 TCP 요청을 날린다. <ol>
<li>3-way handshake 과정을 거쳐 http 요청을 날리게 된다.</li>
</ol>
</li>
<li>서버 측에서 클라이언트로 HTTP 응답 메세지를 전송한다.</li>
<li>이렇게 받은 html 문서를 브라우저에 넣어준다.<ol>
<li>브라우저에서는 html 문서를 파싱하여 DOM 트리를 구축하고 CSS 파일 링크를 찾아 CSSOM 트리를 구축한다.</li>
<li>둘을 사용해 렌더 트리를 구축한다.</li>
<li>렌더트리를 이용해 각 노드들의 위치를 지정하는 레이아웃 과정을 거친다.</li>
<li>화면에 paint 한다.</li>
</ol>
</li>
</ol>
<h3 id="✅dns">✅DNS</h3>
<p><u>Domain name을 IP 주소로 바꿀 수 있도록 도와주는 분산 시스템</u>을 의미합니다. </p>
<p>도메인 주소는 <code>.</code>을 기준으로 나뉘게 되며, 가장 오른쪽에서 부터 해석됩니다. 이러한 도메인 주소는 통으로 관리되는 것이 아니라, 트리 구조로 분리한 다음 관리하게 되는데, 이 전체 트리 구조를 <code>도메인 네임 스페이스</code>라 부르고 각각의 도메인을 네임서버가 처리하게 됩니다.</p>
<p>실제로 DNS가 동작하는 방식은, 먼저 리졸버가 사용자로부터 요청 받은 domain name을 가지고 네임 서버에 DNS 쿼리를 날립니다. 네임 서버는 해당 domain을 가지고 IP주소를 찾아 리졸버에게 넘겨줍니다.  리졸버는 DNS 서버로부터 최종 결과를 응답 받아 웹 브라우저로 전달합니다.</p>
<h3 id="✅응답-상태-코드">✅응답 상태 코드</h3>
<p>응답 상태 코드는 <u>특정 HTTP 요청이 성공적으로 완료되었는지 알려줍니다</u>. 이러한 상태코드는 응답의 의미에 따라 5가지로 나뉩니다.</p>
<p>현재 작업의 진행상황과 관련된 정보를 알려주는<code>1xx</code>,</p>
<p>요청이 성공적으로 받아들여졌음을 의미하는  <code>2xx</code>,</p>
<p>요청이 완료되기 위해선 리다이렉트가 필요함을 의미하는 <code>3xx</code>,</p>
<p>클라이언트의 요청이 올바르지 않는 것을 의미하는  <code>4xx</code>,</p>
<p>서버 쪽에서 처리하는데 문제가 생겼음을 암시하는 <code>5xx</code> </p>
<p>대표적인 응답 상태 코드로는 </p>
<p>get 요청을 잘 받았음을 의미하는 <code>200</code>,</p>
<p>post 요청이 성공적으로 되었음을 의미하는 <code>201</code>,</p>
<p>csrf token을 받지 못했을 때 발생하는 forbidden <code>403</code>,</p>
<p>요청한 페이지가 없음을 의미하는 <code>404</code> 등이 있습니다.</p>
<h3 id="✅get-post-방식의-차이">✅GET, POST 방식의 차이</h3>
<p>GET 방식은 클라이언트에서 서버로 어떤 자원을 요청하기 위해 사용하는 메서드 이며, POST 방식은 클라이언트에서 서버로 자원을 저장하기 위해 데이터를 보낼 때 사용하는 메서드 입니다. </p>
<p><u>GET은 요청 메시지에 body가 없지만, POST는 body에 데이터를 담아 보냅니다. 이러한 GET 요청은 몇 번을 요청해도 결과가 똑같지만, POST는 여러 번 요청하면 리소스가 새로 생성되거나 업데이트 되기 때문에 멱등이 아닙니다.</u></p>
<h3 id="✅keepalive">✅KeepAlive</h3>
<p>HTTP는 기본적으로 connectionless입니다. 한번 요청 후 응답을 받으면 연결을 끊어버립니다. 이러한 <u>연결을 끊지 않고 계속 요청을 보낼 수 있도록 하는 것</u>이 keepalive 입니다. 이는 <code>Connection</code>과 <code>Keep-Alive</code> 헤더를 설정하여 사용할 수 있다. keepalive를 사용함으로써 3-way handshake로 인한 지연 시간을 줄일 수 있습니다.</p>
<h3 id="✅무상태성">✅무상태성</h3>
<p><u>HTTP에서 서버가 클라이언트의 상태를 보존하지 않는 것</u>을 의미합니다. 서버의 개수가 많아지면 그만큼 정보를 많이 공유해야 하기 때문에 비싸질 수 밖에 없는데, stateless하게 사용하면 정보 공유가 최소화되어 비용 절감이 가능합니다.</p>
<h3 id="✅공인-ip와-사설-ip의-차이">✅공인 IP와 사설 IP의 차이</h3>
<p>공인 IP란 ISP(인터넷 서비스 공급자)가 제공하는 IP 주소이며, 외부에 공개되어 있는 IP 주소를 의미합니다. 사설 IP란 일반 가정이나 회사 내에서 할당된 IP 주소를 의미하며 공유기(라우터)에 로컬 네트워크 상의 PC나 장치에 할당됩니다.</p>
<p><u>공인 IP의 경우 전 세계에서 유일하지만, 사설 IP는 하나의 네트워크 안에서 유일합니다.</u> <u>공인 IP는 외부, 내부 상관없이 해당 IP에 접속할 수 있으나, 사설 IP는 내부에서만 접근이 가능합니다</u>.</p>
<p>이렇게 사설IP로 연결된 PC에서 외부 네트워크에 통신을 하려면 라우터가 이를 사설 IP를 공인 IP로 변환하고 응답받은 공인 IP 주소를 다시 사설 IP로 변환하는 기술을 NAT(Network Address Translation)이라 부릅니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] Promise 이해하기]]></title>
            <link>https://velog.io/@lea-hwang/JavaScript-Promise-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@lea-hwang/JavaScript-Promise-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 15 Apr 2023 12:11:02 GMT</pubDate>
            <description><![CDATA[<h1 id="promise">Promise</h1>
<p><code>Promise</code>란 <strong>비동기 처리</strong>를 위해 사용되는 <code>객체</code>이다! </p>
<p>그렇기 때문에 <strong>생성자 함수를 통해 Promise 객체를 만들어 낼 수 있다</strong>. </p>
<h3 id="promise-객체-생성">Promise 객체 생성</h3>
<p>예시를 통해 살펴보자.</p>
<pre><code class="language-javascript">const promise = new Promise((resolve, reject) =&gt; {
    try {
        // 비동기적으로 처리되는 함수가 이곳에 정의된다.
        setTimeout(() =&gt; resolve(res), 3000); // 정상적으로 처리가 되었을 경우 resolve 함수 실행    
    } catch (err) { // error 발생시 reject 실행
        reject(err);        
    }
});</code></pre>
<ul>
<li><p><code>Promise</code>는 <strong>객체</strong>이기 때문에 <code>new</code>를 통해 생성할 수 있으며, <code>Promise()</code>라는 생성자 함수로 만들 수 있다.</p>
</li>
<li><p>생성자 함수의 첫 번째 인자로 &quot;콜백 함수&quot;를 넘겨야 한다. </p>
<ul>
<li>안 넘기면 다음과 같은 에러가 발생한다.</li>
</ul>
</li>
</ul>
<p><img src="assets/image-20230415153125682.png" alt="image-20230415153125682"></p>
<ul>
<li>콜백 함수의 인자로는 <code>resolve</code>와 <code>reject</code>라는 두 개의 인자를 넘겨야 한다.<ul>
<li><strong>resolve</strong>는 콜백함수 내부에서 내부 연산(비동기 처리)이 <code>성공</code>했을 때 실행시킬 함수이다.</li>
<li><strong>reject</strong> 는 콜백 함수 내부에서 내부 연산(비동기 처리)이 <code>실패</code>했을 때 실행시킬 함수이다.</li>
</ul>
</li>
</ul>
<h3 id="promise-상태">Promise 상태</h3>
<p><img src="assets/promises-1681552457784-4.png" alt="img"></p>
<p><code>Promise</code>의 상태는 총 세 가지이다. </p>
<ol>
<li>대기(<em>pending)</em>: 이행하지도, 거부하지도 않은 초기 상태.</li>
<li>이행(<em>fulfilled)</em>: 연산이 성공적으로 완료됨.</li>
<li>거부(<em>rejected)</em>: 연산이 실패함.</li>
</ol>
<blockquote>
<p> Promise의 내부 연산이 성공했을 때(<code>fulfilled</code>), 그 결과를 <code>resolve</code>함수를 통해 받을 수 있다. </p>
<p>반대로 Promise의 내부 연산이 실패했을 때(<code>rejected</code>), 그 실패의 원인이 되는 에러를 <code>reject</code> 함수를 통해 받을 수 있다. </p>
</blockquote>
<h3 id="promise-처리기">Promise 처리기</h3>
<p>Promise의 내부적으로 (비동기) 처리된 결과 값들을 받아 별도로 처리하기 위해선, <code>.then</code>, <code>.catch</code> 처리기를 사용해야 한다. </p>
<ul>
<li><p><code>Promise.prototype.then(fulfilledCallback [, rejectedCallback])</code></p>
<pre><code class="language-javascript">// promise는 프로미스 객체
promise.then(
    () =&gt; {}, // fulfilled 되었을 때 실행될 콜백 
    () =&gt; {}  // rejected 되었을 때 실행될 콜백
);</code></pre>
<ul>
<li><p>Promise에 이행 또는 거부 콜백을 추가한다.</p>
<ul>
<li>콜백이 호출되는 경우<ul>
<li><code>이행</code>: 첫번째 인자로 전달된 콜백이 실행된다. resolve의 인자가 콜백의 인자로 넘겨진다.</li>
<li><code>거부</code>: 두번째 인자로 전달된 콜백이 실행된다. reject의 인자가 콜백의 인자로 넘겨진다.</li>
</ul>
</li>
<li>콜백이 호출되지 않는 경우(넘겨진 콜백이 상수이거나 하는 상황)<ul>
<li>처리된 값과 상태 그대로 처리되는 새로운 프로미스를 반환한다.</li>
</ul>
</li>
</ul>
</li>
<li><p><code>.then</code>은 <strong>새로운 Promise 객체</strong>이기 때문에 <code>.then</code>이나 <code>.catch</code>를 붙일 수 있다.</p>
<ul>
<li><p>콜백함수가 값을 반환할 경우, 그 반환 값을 자신의 결과 값으로 한 이행된 Promise 객체가 반환된다. </p>
<p><img src="assets/image-20230415180044394-1681552465293-6.png" alt="image-20230415180044394"></p>
</li>
<li><p>콜백함수가 값을 반환하지 않을 경우, <code>undefined</code> 를 결과 값으로 하여 이행된 Promise 객체가 반환된다.</p>
<p><img src="assets/image-20230415181822109-1681552468678-8.png" alt="image-20230415181822109"></p>
</li>
<li><p>오류가 발생한 경우, 그 오류를 자신의 결과 값으로 하여 거부된 Promise 객체가 반환된다.</p>
<p><img src="assets/image-20230415181808792-1681552471761-10.png" alt="image-20230415181808792"></p>
</li>
<li><p><strong>대기 중인</strong> Promise 객체를 반환할 경우, 그 Promise의 이행 여부와 결과값을 따른 프로미스를 반환한다.</p>
</li>
<li><p>이미 이행한 Promise 객체를 반환할 경우, 그 프로미스의 결과값을 자신의 결과값으로 하여 이행한 프로미스를 반환한다.</p>
</li>
<li><p>이미 거부된 Promise 객체를 반환할 경우, 그 프로미스의 결과값을 자신의 결과값으로 하여 거부한 프로미스를 반환한다.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><code>Promise.prototype.catch(rejectedCallback)</code> </p>
<pre><code class="language-javascript">// promise는 Promise 객체
promise.catch(
    () =&gt; {}  // rejected 되었을 때 실행될 콜백
);</code></pre>
<ul>
<li><p>Promise에 거부 콜백을 추가한다.</p>
<ul>
<li><p>이전 프로미스가 거부되었을 때, 그 반환값으로 이행된다.(거부되는 것이 아니다.) reject의 인자가 콜백의 인자로 넘겨진다.</p>
<p><img src="assets/image-20230415182635270-1681552475427-12.png" alt="image-20230415182635270"></p>
</li>
<li><p>이전 프로미스가  이행되는 경우, 이행한 값을 그대로 사용해 새로운 프로미스를 반환한다.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="promise의-동작-예시">Promise의 동작 예시</h3>
<p> 다음과 같은 예시를 살펴보자.</p>
<pre><code class="language-javascript">const promise = new Promise((resolve, reject) =&gt; { // 1
    console.log(&quot;promise&quot;); // 2
    try {
        setTimeout(() =&gt; { // 3
            console.log(&quot;setTimeout&quot;); // 7
            resolve(400); // 8
        }, 3000)
    } catch (err) {
        reject(err);
    }
}); // 4
console.log(promise); // 5
console.log(&quot;promise 다음&quot;); // 6
promise
    .then(data =&gt; {
        console.log(data);
        console.log(promise);
        return 300;
    }) // 8
    .catch(err =&gt; console.log(err)) // 9
    .then((data) =&gt; console.log(data));  // 10</code></pre>
<p><img src="assets/image-20230415183546764.png" alt="image-20230415183546764"></p>
<p>위 그림의 실행순서는 다음과 같다.(실행 컨텍스트까지 들어가지는 않겠다.)</p>
<ol>
<li>Promise 객체가 생성된다. 객체가 생성됨과 동시에 Promise에 전달된 콜백함수가 실행된다. </li>
<li>&quot;promise&quot;가 출력된다.</li>
<li>setTimeout 함수(비동기 함수)가 실행된다.</li>
<li>만들어진 Promise 객체가 <code>promise</code> 변수에 담긴다.</li>
<li><code>promise</code>가 콘솔창에 출력된다.<ul>
<li>Promise의 상태가 <code>pending</code>으로 나오는 것을 확인할 수 있다.</li>
</ul>
</li>
<li>&quot;promise 다음&quot; 이 출력된다.</li>
<li>일정 시간이 지난 뒤 &quot;setTimeout&quot; 이 출력된다.</li>
<li>promise의 첫번째 then의 콜백으로 전해졌던 함수가 실행된다.<ul>
<li>resolve 함수의 인자로 전달된 값이 <code>data</code>로 넘겨진다.</li>
<li><code>promise</code>가 콘솔 창에 출력되는데, Promise의 상태가 <code>fulfilled</code>로 나오는 것을 확인할 수 있다.</li>
<li>300을 반환한다.</li>
</ul>
</li>
<li>이전 프로미스가 fulfilled 되었기 때문에 내부 콜백이 실행되지 않는다.<ul>
<li>이전 프로미스에서 받은 결과값을 그대로 Promise 객체로 만들어 이행한다.</li>
</ul>
</li>
<li>넘겨받은 결과값을 출력한다.</li>
</ol>
<p>이 예시로 알 수 있는 것은 다음과 같다.</p>
<ol>
<li>Promise 객체가 생성되었을 때 전달된 콜백함수를 바로 실행시킨다.</li>
<li>해당 Promise 객체 내부 연산이 처리될 때까지는 <code>pending</code>(대기) 상태를 유지하다가 처리되면 <code>fulfilled</code> 상태로 변한다.</li>
<li><code>.then</code>의 콜백이 <code>resolve</code> 함수처럼 처리된다.</li>
<li><code>.catch</code>의 이전 프로미스가 <code>fulfilled</code>되기 때문에 내부 콜백이 실행되지 않고 이전 프로미스의 결과값을 이어받아 Promise 객체를 반환한다.</li>
</ol>
<h3 id="promise의-사용">Promise의 사용</h3>
<p>보통의 Promise 객체는 변수에 바로 할당되기 보다는 return 값으로 전달된다. 이는 Promise 객체는 생성될 때 바로 해당 Promise 내부 콜백을 실행시키기 때문이다. 아래의 예시를 확인해보자.</p>
<p><img src="assets/image-20230415184903455-1681552483622-14.png" alt="image-20230415184903455"></p>
<p>Promise 객체를 return 하는 함수 <code>promise</code>는 호출될 때마다 프로미스 객체가 생성하고 내부 콜백이 실행된다. 이를 통해 원하는 시점에 비동기 함수를 실행할 수 있도록 하는 것이다.</p>
<blockquote>
<p> <code>fetch</code>, <code>axios</code> 등 백엔드에 API 요청을 날리는 함수들은 이러한 Promise 객체를 리턴한다.</p>
<p><img src="assets/image-20230415185345839.png" alt="image-20230415185345839"></p>
</blockquote>
<p><strong>참고 자료</strong></p>
<p><a href="https://yoo11052.tistory.com/155">https://yoo11052.tistory.com/155</a></p>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/then</a></p>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise">https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 1007번: 벡터 매칭, 
시간 초과의 늪]]></title>
            <link>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-1007%EB%B2%88-%EB%B2%A1%ED%84%B0-%EB%A7%A4%EC%B9%AD-%E3%85%85</link>
            <guid>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-1007%EB%B2%88-%EB%B2%A1%ED%84%B0-%EB%A7%A4%EC%B9%AD-%E3%85%85</guid>
            <pubDate>Tue, 24 Jan 2023 04:27:41 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lea-hwang/post/eb00e1e4-74d0-45d5-8714-1a594c9f33c5/image.png" alt="">
시간 초과의 늪에 빠져 결국 다른 분의 코드를 보았다.ㅠㅠ</p>
<p>처음에는 2개씩 짝을 짓는 dfs(재귀)로 풀어보고자 했다.</p>
<pre><code class="language-python"># 2개씩 N/2의 쌍을 만들어서 풀이.
import sys
input = sys.stdin.readline

T = int(input())


def add_vector(a, b):
    return (a[0] + b[0], a[1] + b[1])


def make_vector(i, j):
    dot_a, dot_b = dots[i], dots[j]
    return (dot_b[0] - dot_a[0], dot_b[1] - dot_a[1])


def get_distance(v):
    return (v[0]**2 + v[1]**2)**(1 / 2)


def dfs(is_selected, cur, cnt, v):
    global N, min_sum_vector
    # 모두 선택되었을 경우
    if cnt == N:
        min_sum_vector = min(min_sum_vector, get_distance(v))
        return
    i = is_selected.index(False, cur, N)
    is_selected[i] = True
    for j in range(i + 1, N):
        if not is_selected[j]:
            is_selected[j] = True
            v_x, v_y = make_vector(i, j)
            dfs(is_selected, i + 1, cnt + 2, add_vector(v, (v_x, v_y)))
            dfs(is_selected, i + 1, cnt + 2, add_vector(v, (-v_x, -v_y)))
            is_selected[j] = False
    is_selected[i] = False
    return


for _ in range(T):
    N = int(input())
    dots = [list(map(int, input().split())) for _ in range(N)]
    min_sum_vector = int(1e9)

    dfs([False] * N, 0, 0, (0, 0))
    print(min_sum_vector)
</code></pre>
<p>그러나 시간 초과가 나서, N/2개의 숫자를 먼저 뽑는 방식으로 다시 풀어보았다. 또한 벡터의 합을 구하는 데, 몇가지 특징이 있어 그것도 함께 적용해 보았다.
참고 <a href="https://nerogarret.tistory.com/21">https://nerogarret.tistory.com/21</a></p>
<pre><code class="language-python"># 2개씩 N/2의 쌍을 만들어서 풀이.
import sys
from itertools import combinations

input = sys.stdin.readline


def distance(a):
    return (a[0]**2 + a[1]**2)**(1 / 2)


T = int(input())

for _ in range(T):
    N = int(input())
    dots = []
    total_sum_vector = [0, 0]
    min_sum_vector = int(1e9)

    # 모든 점 다 더하기
    for _ in range(N):
        a, b = map(int, input().split())
        dots.append([a, b])
        total_sum_vector[0] += a
        total_sum_vector[1] += b

    # 출발점 N/2 개 채택
    for selected_dots in list(combinations(range(0, N), N // 2)):
        start_sum_vector = [0, 0]
        for dot in selected_dots:
            start_sum_vector[0] += dots[dot][0]
            start_sum_vector[1] += dots[dot][1]

            cur_sum_vector = (total_sum_vector[0] - start_sum_vector[0] * 2,
                              total_sum_vector[1] - start_sum_vector[1] * 2)
            min_sum_vector = min(min_sum_vector, distance(cur_sum_vector))
    print(min_sum_vector)
</code></pre>
<p>그러나 이 코드도 시간 초과..ㅠㅠ 다른 분 코드랑 비교해보니, 다른 점은 숫자의 합을 구할때 나는 배열의 0번 인덱스, 1번 인덱스에 들어있는 수에 계속 더한다는 것이었고 다른 분은 그냥 2개의 변수에 따로 더한다는 점이 었다...
그 부분을 수정해서 적용하니.. 바로 통과..</p>
<pre><code class="language-python"># 2개씩 N/2의 쌍을 만들어서 풀이.
import sys
from itertools import combinations
input = sys.stdin.readline


def distance(a):
    return (a[0]**2 + a[1]**2)**(1 / 2)


T = int(input())

for _ in range(T):
    N = int(input())
    dots = []
    x_sum = 0
    y_sum = 0
    total_sum_vector = [0, 0]
    min_sum_vector = int(1e9)

    # 모든 점 다 더하기
    for _ in range(N):
        a, b = map(int, input().split())
        dots.append([a, b])
        x_sum += a
        y_sum += b

    # 출발점 N/2 개 채택
    for selected_dots in list(combinations(dots, N // 2)):
        start_x_sum = 0
        start_y_sum = 0
        for x, y in selected_dots:
            start_x_sum += x
            start_y_sum += y

        cur_sum_vector = (x_sum - start_x_sum * 2,
                              y_sum - start_y_sum * 2)
        min_sum_vector = min(min_sum_vector, distance(cur_sum_vector))
    print(min_sum_vector)
</code></pre>
<p>다음부터는 고려해서 짜보아야겠다..!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Javascript 기본 - 함수]]></title>
            <link>https://velog.io/@lea-hwang/React-Javascript-%EA%B8%B0%EB%B3%B8-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@lea-hwang/React-Javascript-%EA%B8%B0%EB%B3%B8-%ED%95%A8%EC%88%98</guid>
            <pubDate>Tue, 17 Jan 2023 14:53:48 GMT</pubDate>
            <description><![CDATA[<h2 id="함수">함수</h2>
<p><strong>반복되는 코드</strong>를 효율적으로 줄일 수 있다.</p>
<p>직사각형의 면적을 계산한다고 했을 때, 우리는 모든 직사각형의 면적을 계산하기 위해 수없이 많은 식을 작성해야할 것이다. 이처럼 _직사각형을 계산하는 식_을 함수로 만들어서 <strong>반복되는 코드를 줄일 수 있다</strong>.</p>
<pre><code class="language-javascript">let width = 10;
let height = 20;
let area1 = width * height;
console.log(&quot;area1: &quot;, area1);

function getArea(width, height) {
  return width * height;
}
console.log(&quot;area2: &quot;, getArea(3, 5));</code></pre>
<p><code>return</code>을 통해 원하는 값을 반환하여 사용할 수도 있다.</p>
<h2 id="함수-선언식과-함수-표현식">함수 선언식과 함수 표현식</h2>
<p>이러한 함수를 생성하는 방법에는 두가지가 존재한다. <code>함수 선언식</code>, <code>함수 표현식</code></p>
<h3 id="함수-선언식">함수 선언식</h3>
<p><strong>함수 선언식</strong>은 <code>function</code> 뒤에 바로 <strong>함수명</strong>을 작성하고 <code>()</code> 안에 <strong>인자</strong>를 적어 함수를 선언하는 방식을 말한다.</p>
<pre><code class="language-javascript">function hello2() {
  return &quot;안녕하세요 여러분&quot;;
}</code></pre>
<h3 id="함수-표현식">함수 표현식</h3>
<p><strong>함수 표현식</strong>은 함수를 저장할 변수를 하나 먼저 만들고 해당 함수에 익명함수(이름이 없는 함수)를 할당하는 것처럼 표현하는 방식을 말한다.</p>
<pre><code class="language-javascript">let hello1 = function () {
  return &quot;안녕하세요 여러분&quot;;
};</code></pre>
<h2 id="지역변수와-전역변수">지역변수와 전역변수</h2>
<h3 id="지역변수">지역변수</h3>
<p>함수 내부에서 선언된 변수로, 함수 외부에서 접근할 수 없다.</p>
<h3 id="전역변수">전역변수</h3>
<p>함수 외부에서 선언된 변수로, 함수 내부에서 접근할 수 있다.</p>
<p>-&gt; <code>스코프</code> 때문인데, 변수가 함수 내부에서 선언되면 함수레벨 스코프를 갖게 되어 함수 내부에서만 접근할 수 있다. 반대로 외부에서 선언되었다면, 해당 스코프 내에 함수를 포함하고 있기 때문에 더 작은 범위의 스코프에서 해당 변수에 접근할 수 있게 된다.</p>
<h2 id="함수의-호이스팅">함수의 호이스팅</h2>
<p><strong>호이스팅</strong>이란, 코드가 실행되기 전, 변수선언, 함수선언이 스코프의 최상단으로 끌어올린 것과 같은 현상을 말한다.
<strong>함수 선언식은 호이스팅되지만 함수 표현식은 호이스팅되지 않는다.</strong></p>
<pre><code class="language-javascript">console.log(hello2()); // 함수 선언식은 호이스팅됨
// console.log(hello1()); // 함수 표현식은 호이스팅되지 않음

// 함수 표현식
let hello1 = function () {
  return &quot;안녕하세요 여러분&quot;;
};

// 함수 선언식
function hello2() {
  return &quot;안녕하세요 여러분&quot;;
} </code></pre>
<h2 id="화살표-함수">화살표 함수</h2>
<p>익명함수에서 <code>function</code>과 <code>{}</code> 생략하고 <code>=&gt;</code>로 연결한 함수를 말한다. 이를 이용하면 함수 표현식을 좀 더 간결하게 표현할 수 있다.</p>
<pre><code class="language-javascript">let hello3 = () =&gt; &quot;안녕하세요 여러분&quot;;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Javascript 기본 - 조건문]]></title>
            <link>https://velog.io/@lea-hwang/React-Javascript-%EA%B8%B0%EB%B3%B8-%EC%A1%B0%EA%B1%B4%EB%AC%B8</link>
            <guid>https://velog.io/@lea-hwang/React-Javascript-%EA%B8%B0%EB%B3%B8-%EC%A1%B0%EA%B1%B4%EB%AC%B8</guid>
            <pubDate>Tue, 17 Jan 2023 14:04:50 GMT</pubDate>
            <description><![CDATA[<h2 id="if">if</h2>
<p>조건을 만족할 때, <code>if</code>문이 실행된다.
조건을 만족하지 않을 때, <code>else</code>문이 실행된다.</p>
<pre><code class="language-javascript">let a = 3;

if (a &gt;= 7) {
  console.log(&quot;7이상입니다.&quot;);
} else if (a &gt;= 5) {
  console.log(&quot;5이상입니다.&quot;);
} else {
  console.log(&quot;5미만입니다.&quot;);
}</code></pre>
<h2 id="switch">switch</h2>
<p>변수의 값과 동일한 <code>case</code>에 해당하는 구문이 실행된다.
<code>break</code>로 끊어주어야 각각의 코드만 실행된다.
어떠한 <code>case</code>에도 속하지 않다면, <code>default</code>가 실행된다.</p>
<pre><code class="language-javascript">let country = &quot;ko&quot;;
switch (country) {
  case &quot;ko&quot;:
    console.log(&quot;한국&quot;);
    break;
  case &quot;cn&quot;:
    console.log(&quot;중국&quot;);
    break;
  case &quot;jp&quot;:
    console.log(&quot;일본&quot;);
    break;
  default:
    console.log(&quot;미 분류&quot;);
    break;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Javascript 기본 - 연산자]]></title>
            <link>https://velog.io/@lea-hwang/React-Javascript-%EA%B8%B0%EB%B3%B8-%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@lea-hwang/React-Javascript-%EA%B8%B0%EB%B3%B8-%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Mon, 16 Jan 2023 13:48:24 GMT</pubDate>
            <description><![CDATA[<p>연산자는 변수에 어떤 연산을 하기 위해 사용되는 것을 의미한다. javascript의 다양한 연산자에 대해 알아보자. </p>
<h2 id="대입-연산자">대입 연산자</h2>
<p><code>대입 연산자</code>(<code>=</code>)는 변수에 값을 할당하는 역할을 한다.</p>
<pre><code class="language-javascript">let a = 1;
let b = 2;
let c = &#39;1&#39;;
let d = &#39;2&#39;;</code></pre>
<h2 id="산술-연산자">산술 연산자</h2>
<p><code>산술 연산자</code>(<code>+</code>, <code>-</code>, <code>/</code>, <code>*</code>)는 변수끼리의 사칙연산, 즉, 계산을 하는데 사용된다.</p>
<pre><code class="language-javascript">console.log(a + b);  // 3
console.log(a - b);  // -1
console.log(a * b);  // 2
console.log(a / b);  // 0.5</code></pre>
<h2 id="연결-연산자">연결 연산자</h2>
<p><code>연결 연산자</code>(<code>+</code>)는 문자열 두 개를 이어붙이는데 사용된다.</p>
<pre><code class="language-javascript">console.log(c + d);</code></pre>
<h2 id="복합-연산자">복합 연산자</h2>
<p><code>복합연산자</code>(<code>+=</code>, <code>-=</code>, <code>/=</code>, <code>*=</code>)는 계산을 한 후 변수의 값에 바로 할당할 수 있도록 한다. <code>산술연산자</code>와 <code>대입연산자</code>가 합쳐졌다고 생각하면 된다.
즉, <code>a = a + 10</code> 을 줄여 <code>a += 10</code>으로 작성할 수 있도록한다.</p>
<pre><code class="language-javascript">a += 10
console.log(a);</code></pre>
<h2 id="증감-연산자">증감 연산자</h2>
<p><code>증감 연산자</code>(<code>++</code>, <code>--</code>)는 <code>+</code>나 <code>-</code> 두개를 변수 앞 또는 뒤에 붙여 해당 변수의 값이 1만큼 변할 수 있도록 한다. <code>++</code>를 앞에 붙이면 연산이 먼저 실행되어 변수의 값이 하나 커지고 해당 라인이 실행되지만, 뒤에 붙이면 해당 라인이 먼저 실행되고 나중에 변수의 값이 하나 커진다. <code>-</code>의 경우도 동일하다.</p>
<pre><code class="language-javascript">a = 10;
a++;
console.log(a);   // 11
console.log(a--); // 11
console.log(a);   // 10</code></pre>
<h2 id="논리-연산자">논리 연산자</h2>
<p><code>논리연산자</code>(<code>!</code>, <code>&amp;&amp;</code>, <code>||</code>)는 논리식을 판단하여 <code>true</code> 또는 <code>false</code>를 반환한다.
<code>!</code>은 <code>NOT</code>을 의미하며, 뒤에 붙은 값의 반대 값을 반환한다. 즉, 뒤의 값이 <code>true</code>이면 <code>false</code>를, <code>false</code>이면 <code>true</code>를 반환한다.
<code>&amp;&amp;</code>는 <code>AND</code>를 의미하며 앞과 뒤의 식이 모두 <code>true</code>일 때만, <code>true</code>를 반환한다.
<code>||</code>는 <code>OR</code>를 의미하며, 앞과 뒤의 식이 모두 <code>false</code>일 때만, <code>false</code>를 반환한다.</p>
<pre><code class="language-javascript">console.log(!true); // false
console.log(true &amp;&amp; true); // true
console.log(true || false); // true
console.log(!!undefined); // false</code></pre>
<h2 id="비교-연산자">비교 연산자</h2>
<p><code>비교연산자</code>(<code>==</code>, <code>===</code>)는 앞과 뒤의 식이 같은지 다른지 여부를 비교하는 연산자이다.
<code>==</code>는 값만 비교하고, <code>===</code>는 값과 타입을 같이 비교하기 때문에 무언가를 비교하고자 할 때는, 특별한 상황이 아니라면<code>===</code>을 쓰는 것이 좋다.</p>
<pre><code class="language-javascript">let compareA = 1 == &quot;1&quot;;
console.log(compareA); // true

let compareB = 1 === &quot;1&quot;;
console.log(compareB); // false

let compareC = 1 &lt;= 2;
console.log(compareC); // true</code></pre>
<h2 id="typeof-연산자">typeof 연산자</h2>
<p><code>typeof</code>는 변수의 타입을 리턴하는 연산자이다.</p>
<pre><code class="language-javascript">console.log(typeof a); // number</code></pre>
<h2 id="null-병합-연산자">null 병합 연산자</h2>
<p><code>null 병합 연산자</code>(<code>??</code>)는, 왼쪽 피연산자의 값이 <code>null</code>이나 <code>undefined</code>일 경우, 오른쪽 피연산자를 반환한다. 그렇지 않을 경우 왼쪽 피연산자 값을 반환한다.</p>
<pre><code class="language-javascript">let k;
k = k ?? 10; 
console.log(k)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Javascript 기본 - 자료형과 형변환]]></title>
            <link>https://velog.io/@lea-hwang/React-Javascript-%EA%B8%B0%EB%B3%B8-%EC%9E%90%EB%A3%8C%ED%98%95%EA%B3%BC-%ED%98%95%EB%B3%80%ED%99%98</link>
            <guid>https://velog.io/@lea-hwang/React-Javascript-%EA%B8%B0%EB%B3%B8-%EC%9E%90%EB%A3%8C%ED%98%95%EA%B3%BC-%ED%98%95%EB%B3%80%ED%99%98</guid>
            <pubDate>Mon, 16 Jan 2023 13:26:22 GMT</pubDate>
            <description><![CDATA[<h2 id="자료형">자료형</h2>
<p>자료형이란, <strong>데이터가 어떻게 메모리에 저장되고 프로그램에서 어떻게 처리되어야 하는지 명시적으로 알려주는 것</strong>을 말한다. 간단히 말하면 데이터의 종류 혹은 타입이라 말할 수 있다.</p>
<p>자바스크립트에는 기본형, 참조형 타입 두 가지 타입이 존재한다.</p>
<h3 id="primitive-data-type기본형-원시형">Primitive Data Type(기본형, 원시형)</h3>
<p>변수에 데이터가 할당될 때, 메모리 상에 고정된 크기로 저장되고 해당 변수가 <strong>데이터 값</strong>을 보관한다. 모든 변수 선언, 초기화, 할당 시, 해당 <strong>메모리 영역에 직접 접근</strong>하여 값을 변경한다. 
즉, 한 번에 하나의 값만 가질 수 있고 하나의 저장공간을 사용한다는 것을 의미한다.</p>
<p>Primivtive Data Type에는 <code>number</code>, <code>string</code>, <code>boolean</code>, <code>undefined</code>, <code>null</code> 이 존재한다.</p>
<h4 id="number숫자형">Number(숫자형)</h4>
<p><code>Number</code>에는 <code>int</code>, <code>float</code>, <code>infinity</code>(<code>positive</code>, <code>negative</code>), NaN(<code>Not a Number</code>)를 포함하고 있다.</p>
<pre><code class="language-javascript">let age = 25;         // 정수
let tall = 160.4;     // 실수
let inf = Infinity;   // 무한대
let nan = NaN;        // not a number

console.log(age + tall); // 185.4</code></pre>
<h4 id="string문자형">String(문자형)</h4>
<p><code>String</code>은 <code>&quot;&quot;</code>, <code>&#39;&#39;</code>로 감싸 표현할 수 있다. 만약 변수가 포함된 문자열을 만들고 싶을 때는 <code>``</code>로 전체 문자열을 감싸고 그 속에 변수를 <code>${변수명}</code>과 같은 형식으로 넣어주면 된다.</p>
<pre><code class="language-javascript">let name = &quot;lea&quot;;
let name2 = &#39;황희원&#39;;
let name3 = `lea ${name2}`;

console.log(name3); // lea 황희원</code></pre>
<h4 id="boolean불린형">Boolean(불린형)</h4>
<p><code>Boolean</code>은 <code>true</code>, <code>false</code>을 일컫는 자료형이다.</p>
<pre><code class="language-javascript">let isGood = true;
console.log(isGood);</code></pre>
<h4 id="undefinedundefined-타입">Undefined(undefined 타입)</h4>
<p><code>Undefined</code>는 <strong>아무 값도 할당하지 않았을 경우</strong>를 의미하는 자료형이다. 만약 변수를 선언만 하고 아무런 값도 할당하지 않았다면, 그 변수는 <code>undefined</code>를 갖게 된다.</p>
<pre><code class="language-javascript">let b;
console.log(b);</code></pre>
<h4 id="null널-타입">Null(널 타입)</h4>
<p><code>Null</code>은 <strong>의도적으로 아무 값도 가지고 있지 않다</strong>라는 것을 의미한다. <code>undefined</code>와는 조금 의미가 다르다. 이전에 할당되어있던 값을 <code>null</code>로 바꾸어 명시적으로 참조를 제거하는 것을 의미한다.</p>
<pre><code class="language-javascript">let a = null;
console.log(a);</code></pre>
<h3 id="non-primitive-data-type참조형-비원시형">Non-Primitive Data Type(참조형, 비원시형)</h3>
<p><code>Non-Primitive Type</code>은 <strong>한 번에 여러 개의 값을 가질 수 있고 여러 개의 고정되지 않은 동적 공간을 사용</strong>한다.</p>
<h4 id="object">Object</h4>
<p>이후 글에서 따로 다룰 예정이다.</p>
<h4 id="array">Array</h4>
<p>이후 글에서 따로 다룰 예정이다.</p>
<h4 id="function">Function</h4>
<p>이후 글에서 따로 다룰 예정이다.</p>
<p><img src="https://velog.velcdn.com/images/lea-hwang/post/4190972e-8dc8-4f2d-8e35-bcc8b254e07d/image.png" alt="Data Types"></p>
<h2 id="형변환">형변환</h2>
<h3 id="묵시적-형변환">묵시적 형변환</h3>
<p><code>묵시적 형변환</code>이란, 자바스크립트가 알아서 자료형을 바꿔주는 것을 의미한다.</p>
<pre><code class="language-javascript">let k = 12;
let m = &quot;2&quot;;
console.log(k * m); // 24 
console.log(k + m); // 122</code></pre>
<h3 id="명시적-형변환">명시적 형변환</h3>
<p><code>명시적 형변환</code>이란, 프로그래머가 의도적으로 형변환하는 것을 의미한다.</p>
<pre><code class="language-javascript">let k = 12;
let m = &quot;2&quot;;

console.log(k + parseInt(m)); // 14</code></pre>
<h2 id="참고">참고</h2>
<p><a href="https://hanamon.kr/javascript-undefined-null-%EC%B0%A8%EC%9D%B4%EC%A0%90/">[JavaScript] undefined 타입 &amp; null 타입 차이점</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 15681번: 트리와 쿼리]]></title>
            <link>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-15681%EB%B2%88-%ED%8A%B8%EB%A6%AC%EC%99%80-%EC%BF%BC%EB%A6%AC</link>
            <guid>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-15681%EB%B2%88-%ED%8A%B8%EB%A6%AC%EC%99%80-%EC%BF%BC%EB%A6%AC</guid>
            <pubDate>Fri, 13 Jan 2023 03:28:05 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/15681">트리와 쿼리</a></p>
<p><img src="https://velog.velcdn.com/images/lea-hwang/post/6e10ba0d-ad10-491e-b8a6-bb74efb7c84d/image.png" alt="">
<img src="https://velog.velcdn.com/images/lea-hwang/post/b7656830-b6de-49ba-8c92-f108e57abb68/image.png" alt=""></p>
<p>힌트에 굉장히 좋은 코드가 있어서 따로 정리하려 한다.</p>
<h2 id="루트가-없는-트리-만들기">루트가 없는 트리 만들기</h2>
<p>트리의 루트 노드가 정해져 있지 않아, 하나를 루트노드로 정해서 트리를 만들고자 할때 유용한 함수이다.</p>
<p><code>makeTree(5, -1)</code>을 실행하게 되면 root가 5인 트리를 만들 수 있게 된다. -1은 부모가 없음을 의미한다.</p>
<pre><code class="language-python">def makeTree(currentNode, parent) :
    for(Node in connect[currentNode]) :
        if Node != parent:
            add Node to currentNode’s child
            set Node’s parent to currentNode
            makeTree(Node, currentNode)</code></pre>
<h2 id="특정-정점을-루트로-하는-서브트리에-속한-정점의-수를-계산">특정 정점을 루트로 하는 서브트리에 속한 정점의 수를 계산</h2>
<p>계산하는 방식은 다음과 같다.</p>
<blockquote>
<ol>
<li>먼저 <code>V</code>을 루트로 하는 서브트리에 포함된 노드들의 개수를 저장할 <code>size</code> 리스트를 만든다.</li>
<li>현재 노드인<code>V</code>(루트 노드)도 해당 서브트리에 포함되므로, <code>size</code>에 +1을 해준다.</li>
<li>현재 노드의 서브트리에 포함된 노드의 개수를 구하고 이를 <code>size</code>에 더해준다.</li>
</ol>
</blockquote>
<p>만약 자식이 없다면, 즉 리프노드라면 child가 없고 서브트리에 본인만 있기 때문에 size는 1이다. 재귀적으로 다시 돌아가며 서브트리의 노드의 개수를 구할 수 있다.</p>
<pre><code class="language-python">def countSubtreeNodes(currentNode) :
    size[currentNode] = 1 // 자신도 자신을 루트로 하는 서브트리에 포함되므로 0이 아닌 1에서 시작한다.
    for Node in currentNode’s child:
        countSubtreeNode(Node)
        size[currentNode] += size[Node]     </code></pre>
<h2 id="문제-풀이">문제 풀이</h2>
<p>처음 주어진 root를 기준으로 트리를 만들고, 각 노드의 서브트리의 개수를 미리 세는 방식을 선택했다.</p>
<pre><code class="language-python">import sys
sys.setrecursionlimit(10**6)
input = sys.stdin.readline

N, R, Q = map(int, input().split())  # 트리의 정점의 수, 루트의 번호, 쿼리의 수
adjM = [[] for _ in range(N + 1)]  # 간선 정보를 저장할 행렬
children = [[] for _ in range(N + 1)]  # 자식 정보를 저장할 리스트
size = [0] * (N + 1)

for _ in range(N - 1):
    e1, e2 = map(int, input().split())
    adjM[e1].append(e2)
    adjM[e2].append(e1)


def make_tree(current, parent):
    for near in adjM[current]:
        if near != parent:
            children[current].append(near)
            make_tree(near, current)


def count_sub(current):
    size[current] = 1
    for child in children[current]:
        count_sub(child)
        size[current] += size[child]


make_tree(R, -1)
count_sub(R)

for _ in range(Q):  # 각 쿼리에 대한 답 찾기
    root = int(input())
    print(size[root])</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm]Java로 입력받기]]></title>
            <link>https://velog.io/@lea-hwang/AlgorithmJava%EB%A1%9C-%EC%9E%85%EB%A0%A5%EB%B0%9B%EA%B8%B0</link>
            <guid>https://velog.io/@lea-hwang/AlgorithmJava%EB%A1%9C-%EC%9E%85%EB%A0%A5%EB%B0%9B%EA%B8%B0</guid>
            <pubDate>Wed, 11 Jan 2023 02:32:37 GMT</pubDate>
            <description><![CDATA[<h3 id="파일로-입력-받기-위한-package">파일로 입력 받기 위한 package</h3>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;
public static void main(String args[]) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
}
</code></pre>
<h3 id="숫자-하나-입력받기">숫자 하나 입력받기</h3>
<p><strong>예시 입력</strong></p>
<pre><code class="language-txt">1</code></pre>
<p><strong>자바 코드</strong></p>
<pre><code class="language-java">K = Integer.parseInt(br.readLine());</code></pre>
<h3 id="띄어쓰기된-수-입력받기">띄어쓰기된 수 입력받기</h3>
<p><strong>예시 입력</strong></p>
<pre><code class="language-txt">2 3</code></pre>
<p><strong>자바 코드</strong></p>
<pre><code class="language-java">StringTokenizer st = new StringTokenizer(br.readLine());
row = Integer.parseInt(st.nextToken());
col = Integer.parseInt(st.nextToken());</code></pre>
<h3 id="띄어쓰기-없는-문자열여러-줄-입력받기">띄어쓰기 없는 문자열(여러 줄) 입력받기</h3>
<p><strong>예시 입력</strong></p>
<pre><code>ABCD
ARSF
OJES</code></pre><p><strong>자바 코드</strong></p>
<pre><code class="language-java">mat = new char[row][col];
for (int i = 0; i &lt; row; i++){
    char[] line = br.readLine().toCharArray();
    mat[i] = line;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Javascript 기본 - 변수와 상수]]></title>
            <link>https://velog.io/@lea-hwang/React-%ED%95%9C%EC%9E%85-%ED%81%AC%EA%B8%B0%EB%A1%9C-%EC%9E%98%EB%9D%BC-%EB%A8%B9%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8React.js-Javascript-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@lea-hwang/React-%ED%95%9C%EC%9E%85-%ED%81%AC%EA%B8%B0%EB%A1%9C-%EC%9E%98%EB%9D%BC-%EB%A8%B9%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8React.js-Javascript-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Mon, 19 Dec 2022 10:33:04 GMT</pubDate>
            <description><![CDATA[<p>과거의 자바스크립트에서는 <code>var</code>를 이용해 변수를 선언하였다. 그러나 <code>var</code>를 사용하게 되면 몇가지 문제 상황이 발생하여 <code>let</code>, <code>const</code> 사용을 권하고 있다. 그렇다면, <code>let</code>과 <code>const</code>는 각각 어떠한 역할을 하는지 알아보자.</p>
<h3 id="let">let</h3>
<p>값이 변할 수 있는 데이터 공간. 즉, <strong>변수</strong>를 저장할 수 있게 한다.</p>
<pre><code class="language-javascript">let age = 25;
console.log(age);

age = 30;
console.log(age);</code></pre>
<h3 id="const">const</h3>
<p>일정한 값을 저장하는 데이터 공간. 즉, <strong>변하지 않는 상수</strong>를 의미한다.</p>
<p>상수는 한번 선언된 이후, 새롭게 할당할 수 없다. 할당하고자 한다면 에러가 발생한다.</p>
<pre><code class="language-javascript">const name = &#39;희원&#39;;
name = &#39;예지&#39;; // -&gt; TypeError: &quot;name is read-only&quot;</code></pre>
<p>그러나 객체 내에서의 변수값 변경은 가능하다. 이 내용은 이후 글에서 다루도록 하겠다.</p>
<h4 id="변수명-규칙">변수명 규칙</h4>
<p>이러한 변수를 지정하는 그 명칭에는 몇가지 규칙이 존재한다.</p>
<ol>
<li>변수에는 <strong>기호를 사용할 수 없다</strong>. (_$ 제외)</li>
<li>반드시 숫자가 아닌 <strong>문자로 시작</strong>해야한다.</li>
<li><strong>예약어</strong>로 변수를 만들 수 없다. (if, for ...)</li>
</ol>
<h3 id="let-vs-var-vs-const">let v.s. var v.s const</h3>
<p>그렇다면 이전에 사용되었던 <code>var</code>과는 어떤 차이점이 있을까?</p>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">let</th>
<th align="center">const</th>
<th align="center">var</th>
</tr>
</thead>
<tbody><tr>
<td align="center">재선언</td>
<td align="center">X</td>
<td align="center">X</td>
<td align="center">O</td>
</tr>
<tr>
<td align="center">재할당</td>
<td align="center">O</td>
<td align="center">X</td>
<td align="center">O</td>
</tr>
<tr>
<td align="center">스코프</td>
<td align="center">블록-레벨</td>
<td align="center">블록-레벨</td>
<td align="center">함수-레벨</td>
</tr>
<tr>
<td align="center">호이스팅</td>
<td align="center">불가능</td>
<td align="center">불가능</td>
<td align="center">가능</td>
</tr>
</tbody></table>
<h4 id="problem1-var는-재선언이-가능해요">Problem1. var는 재선언이 가능해요!</h4>
<p>만약 <strong>재선언</strong>이 가능하다면, 
1000줄이 넘는 코드에서 <strong>똑같은 이름을 가진 변수가 다시 선언되었을 경우, 에러를 보여주지 않아 문제가 발생할 수 있다.</strong></p>
<pre><code class="language-javascript">var height = 160;
console.log(height);

var height = 180;
console.log(height);</code></pre>
<p>-&gt; 동일한 변수를 두번 선언했음에도 해당 코드는 잘 동작한다! :(</p>
<h4 id="problem2-var는-함수-레벨-스코프예요">Problem2. var는 함수-레벨 스코프예요!</h4>
<p><code>const</code>, <code>let</code>은 블록-레벨 스코프이다. </p>
<p>그러나 <code>var</code>는 함수-레벨 스코프이기 때문에, if문 안에서 선언된 변수도 if문 밖(블록스코프 밖)에서 접근할 수 있다.</p>
<pre><code class="language-javascript">if (true) {
  var test = true;
}

alert(test); // true(if 문이 끝났어도 변수에 여전히 접근할 수 있음)</code></pre>
<p>뿐만 아니라, for문에도 동일하게 작용된다.</p>
<pre><code class="language-javascript">for (var i = 0; i &lt; 10; i++) {
  // ...
}

alert(i); // 10, 반복문이 종료되었지만 &#39;i&#39;는 전역 변수이므로 여전히 접근 가능합니다.</code></pre>
<p>이런 <code>var</code>의 특징은 특정 지역변수를 전역변수화시키는 문제가 발생하게 한다.</p>
<h4 id="problem3-var는-호이스팅이-가능해요">Problem3. var는 호이스팅이 가능해요!</h4>
<p><code>Hoisting</code>(호이스팅) 이란, 변수가 최상단으로 끌어올려지는 현상을 의미한다. (<code>hoist</code>는 끌어올리다라는 뜻이 있다.)
<code>var</code>로 변수를 선언할 경우, 선언이 호이스팅이 되어 에러를 발생시키지 않는다. </p>
<pre><code class="language-javascript">function sayHi() {
  phrase = &quot;Hello&quot;;
  alert(phrase);
  var phrase;
}
sayHi();</code></pre>
<p>그러나, 할당은 호이스팅되지 않기 때문에 만약 할당되기 전이라면 <code>undefined</code>가 변수에 담길 것이다.</p>
<pre><code class="language-javascript">function sayHi() {
  var phrase;

  phrase = &quot;Hello&quot;;

  alert(phrase);
}
sayHi();</code></pre>
<h3 id="참고-페이지">참고 페이지</h3>
<p><a href="https://ko.javascript.info/var">오래된 var</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 13022번: 늑대와 올바른 단어]]></title>
            <link>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-13022%EB%B2%88-%EB%8A%91%EB%8C%80%EC%99%80-%EC%98%AC%EB%B0%94%EB%A5%B8-%EB%8B%A8%EC%96%B4</link>
            <guid>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-13022%EB%B2%88-%EB%8A%91%EB%8C%80%EC%99%80-%EC%98%AC%EB%B0%94%EB%A5%B8-%EB%8B%A8%EC%96%B4</guid>
            <pubDate>Wed, 07 Dec 2022 13:39:51 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/13022">백준 13022번: 늑대와 올바른 단어</a></p>
<h3 id="문제">문제</h3>
<blockquote>
<p>다음은 늑대 나라에서 사용하는 올바른 단어에 대한 설명이다.
임의의 양의 정수 n에 대해서, &#39;w&#39;가 n번 나오고, 그 다음에 &#39;o&#39;가 n번, 그 다음에 &#39;l&#39;이 n번, 그 다음에 &#39;f&#39;가 n번 나온 단어는 올바른 단어이다.
올바른 단어 두 개를 이은 단어도 올바른 단어이다.
1번과 2번 조건으로 만들 수 있는 단어만 올바른 단어이다.
다음은 올바른 단어의 예시이다.
1번 규칙으로 만든 &quot;wolf&quot;, &quot;wwoollff&quot;, &quot;wwwooolllfff&quot;는 모두 올바른 단어이다.
2번 규칙으로 만든 &quot;wolfwwoollff&quot;은 올바른 단어이다.
2번 규칙을 두 번 써서 만든 &quot;wolfwwoollffwolf&quot;은 올바른 단어이다.
&quot;wfol&quot;은 올바른 단어가 아니다. (순서가 올바르지 않음)
&quot;wwolfolf&quot;는 올바른 단어가 아니다. (문자열의 중간에 다른 문자열을 집어 넣음)
&quot;wwwoolllfff&quot;는 올바른 단어가 아니다. (o가 2번 들어갔다)</p>
</blockquote>
<h3 id="입력">입력</h3>
<p>첫째 줄에 단어가 주어진다. 단어는 w, o, l, f로만 이루어져 있으며, 길이는 50을 넘지 않는다.</p>
<h3 id="출력">출력</h3>
<p>입력으로 주어진 단어가 올바른 단어인 경우에는 1을, 아니면 0을 출력한다.</p>
<h3 id="풀이방법">풀이방법</h3>
<pre><code class="language-python">import sys
sys.stdin = open(&quot;input.txt&quot;)

word = input()

def check(word):
    while word:
        for i in range(1, 13):
            if len(word) &lt; 4*i:
                return 0
            if word[0:4*i] == &#39;w&#39; * i + &#39;o&#39; * i + &#39;l&#39; * i + &#39;f&#39; * i:
                word = word[4*i:]
                break
        else:
            return 0
    return 1

print(check(word))</code></pre>
<p>처음부터 &#39;wolf&#39;, &#39;wwoollff&#39; ... 단어들을 잘라가면서 진행. 만약 자를 수 없을 때 return 0.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[if(kakao)dev2022 1일차 내용 정리]]></title>
            <link>https://velog.io/@lea-hwang/ifkakaodev2022-1%EC%9D%BC%EC%B0%A8-%EB%82%B4%EC%9A%A9-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@lea-hwang/ifkakaodev2022-1%EC%9D%BC%EC%B0%A8-%EB%82%B4%EC%9A%A9-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 07 Dec 2022 05:57:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lea-hwang/post/e147bbc5-3439-4402-a53f-8f9d1cb09699/image.png" alt=""></p>
<p><a href="https://www.sedaily.com/NewsView/26CCZA33CH">뉴스기사링크</a> </p>
<h2 id="20221015">2022.10.15</h2>
<p>SK C&amp;C 판교 데이터센터에서 화재가 발생하였다. 
(나를 포함한) 많은 사람들이 카카오톡을 비록한 많은 카카오 서비스를 사용할 수 없게 되어 불편함을 겪었다. 그러나, 생각보다 복구에 많은 시간이 걸렸고, 개발자가 되고 싶은 한사람으로서, *<em>화재 발생시 어떠한 문제가 있었기에 빨리 복구되지 않았는지 원인이 너무 궁금했다. *</em></p>
<p>그러던 중 발견한 <strong>카카오 개발자 컨퍼런스</strong>. 
<img src="https://velog.velcdn.com/images/lea-hwang/post/c895602d-3aa9-417a-bde7-8f79ef9817f7/image.png" alt=""></p>
<p><a href="https://if.kakao.com/">https://if.kakao.com/</a>
<del>역시 카카오인가 시작부터 UI.. 너무 멋있다</del></p>
<p>1일차에 <strong>카카오 데이터센터 화재로 인한 서비스 중단과 그에 따른 문제 해결</strong> 관련 내용을 다룬다기에 참가하여 내용을 요약 정리해보기로 하였다.</p>
<h2 id="1010-장애-원인-분석">1010 장애 원인 분석</h2>
<h3 id="장애-상황">장애 상황</h3>
<p>10.15 SK C&amp;C 판교 <strong>데이터센터에서 화재 발생</strong>과 이로 인한 <strong>카카오 서비스 전반의 장애</strong></p>
<h3 id="무엇이-문제였을까">무엇이 문제였을까?</h3>
<p>서비스를 담당하는 서버가 이중화가 되어있었음에도 불구하고 서비스 장애가 발생했고 카카오톡 메세지 수발신 등 주요 기능은 먼저 복구되었지만, 10월 20일 오후 11시 모든 서비스가 복구 완료되기까지 상당한 시일이 걸림. 이는 <strong>이중화와 위기 대응 과정에 미흡함</strong> 때문이었음.</p>
<h3 id="원인-분석-이중화">원인 분석: 이중화</h3>
<blockquote>
<p><strong>이중화</strong>란, 운영 중인 서비스의 안정을 위해 각종 자원(하드웨어, OS, 미들웨어, DB 등)을 이중 혹은 그 이상으로 구성하는 것.</p>
</blockquote>
<h4 id="1-데이터-센터-간-이중화가-미흡">1. 데이터 센터 간 이중화가 미흡.</h4>
<p>데이터 센터 전체에 문제가 생기더라도 다른 데이터센터의 모든 시스템이 이중화가 되어있었다면 빠르게 복구되었을텐데, <strong>일부 시스템이 판교 데이터센터 내에서만 이중화되어 있어서</strong> 장애 복구가 늦어짐.
예로, 서비스를 운영하는 많은 시스템에서 사용되고 있는** 캐시 서버와 오브젝트 스토리지가 완벽하게 이중화되지 않고** 판교 데이터센터에만 설치되어 있어 이를 사용하는 서비스들의 복구가 늦어짐: <em>카카오 로그인 카카오톡의 사진 전송 기능</em>. </p>
<p>서로 다른 데이터센터에 이중화가 되어 있는 경우에도, <strong>하나의 데이터 센터에서 장애가 발생하면 다른 데이터 센터로 자동 전환해 주는 시스템이</strong> 작동해야 하는데 이 시스템마저 <strong>판교 데이터센터에만 설치되어 있었음.</strong> 이에 따라 수동으로 전환 작업을 진행했기 때문에 복구가 늦어짐.</p>
<h4 id="2-시스템을-복구하기-위한-모니터링-시스템의-이중화가-미흡">2. 시스템을 복구하기 위한 모니터링 시스템의 이중화가 미흡</h4>
<p>사용자 서비스에 직접적으로 필요한 시스템 외에 <strong>서비스의 개발과 관리를 위한 운영 관리 도구가 필요한데, 이러한 도구들의 이중화가 미흡함</strong>. 상대적으로 이러한 도구들의 안정성 확보에 소홀하였음.
예를 들어, <em>컨테이너 이미지를 저장하고 관리하는 시스템이나 일부 모니터링 도구</em> 등을 화재 여파로 사용할 수 없게 되어 복구에 상당한 어려움을 겪음.</p>
<h4 id="3-이중화-전환-후-가용-자원의-부족">3. 이중화 전환 후 가용 자원의 부족</h4>
<p><strong>판교 데이터센터 전체를 대신할 만큼의 가용 자원이 확보되어 있지 않았기</strong> 때문에 판교 데이터센터의 전원이 들어와서 모든 시스템이 정상화되기 전까지 복구를 완료할 수 없었음. 전체 시스템의 이중화 수준은 가장 약한 시스템의 이중화 수준을 따라가기 때문에 개별 시스템의 미흡한 이중화가 전체적인 장애를 유발. </p>
<p>개별 부서나 시스템마다 다른 이중화 수준 및 체계 부족한 상면 등으로 문제가 생기지 않도록 회사 차원에서 체계적인 이중화가 필요.</p>
<h3 id="원인-분석-위기-대응">원인 분석: 위기 대응</h3>
<h4 id="1-장애-복구를-위한-인력과-자원이-부족">1. 장애 복구를 위한 인력과 자원이 부족.</h4>
<p><strong>운영 관리 도구의 복구 인력이 부족</strong>했던 것이나 <strong>이중화에 필요한 상면의 부족</strong>이 치명적이었음. 평소 이중화나 장애 대응 체계를 갖추고 있었더라도 이번 서비스 장애와 같이 데이터센터 전체의 장애 상황을 가정하면, 준비가 부족했음.</p>
<h4 id="2-장애-대응을-위한-커뮤니케이션-채널에-혼선이-있었음">2. 장애 대응을 위한 커뮤니케이션 채널에 혼선이 있었음.</h4>
<p>사내 커뮤니케이션과 모니터링 채널로 카카오톡과 카카오 워크를 사용. 해당 서비스를 사용할 수 없을 때, 중요사항 전파 및 의사결정을 위한 <strong>커뮤니케이션 채널이 준비되어 있고 일상적으로 사용되고 있었어야 하나 그러지 못하였음</strong>.</p>
<h4 id="3-재해-초기의-컨트롤-타워의-부재">3. 재해 초기의 컨트롤 타워의 부재</h4>
<p>카카오와 공동체, 그리고 개별 조직이 동시다발적으로 장애에 대응함. 그런데 <strong>전체적인 조율과 협업을 지원하는 전사 조직이 사전에 세팅되어 있지 않았고</strong> 서비스 별로 개발자들이 최선을 다했지만, 그것만으로는 부족했음. </p>
<h3 id="결론-주요원인">결론: 주요원인</h3>
<ol>
<li>데이터센터 간 이중화 미흡</li>
<li>시스템을 복구하기 위한 모니터링 시스템의 이중화가 미흡</li>
<li>하나의 데이터센터 전체의 장애에 대응하기 위한 인력과 자원의 부족</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 1461-도서관]]></title>
            <link>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-1461-%EB%8F%84%EC%84%9C%EA%B4%80</link>
            <guid>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-1461-%EB%8F%84%EC%84%9C%EA%B4%80</guid>
            <pubDate>Mon, 11 Jul 2022 12:49:44 GMT</pubDate>
            <description><![CDATA[<ul>
<li>유형: 그리디</li>
<li>풀이방법:
순서대로 나열 후 음수와 양수 파트를 분리한다.
그 이후 가장 먼 책을 제일 마지막에 꽂는다(한번만 이동하기 위함)
나머지 책들 중, 음수는 작은 수부터 양수는 큰 수부터(절대값이 높은 책부터) 먼저 꽂는다.</li>
<li>유의할 점:
양수, 음수 파트 둘 중 하나라 없는 경우를 고려해야 함.</li>
</ul>
<pre><code class="language-python">import sys
sys.stdin = open(&#39;input.txt&#39;)

N, M = map(int, input().split())
books = list(map(int, input().split()))

books.sort() # 위치 순으로 정리

# 양수, 음수 파트 분리
pos = []
neg = books # 양수 파트가 아예 없는 경우를 대비
for i in range(N):
    if books[i] &gt; 0:
        pos = books[i:]
        neg = books[:i]
        break

total = 0

# 가장 먼 책 마지막에 꽂기
# 왼쪽만 있는 경우
if len(pos) == 0:
    total += -(neg[0])
    neg = neg[M:]
# 오른쪽만 있는 경우
elif len(neg) == 0:
    total += pos[-1]
    pos = pos[:len(pos) - M]
# 둘 다 있는 경우
else:
    if abs(neg[0]) &gt; abs(pos[-1]): # 왼쪽을 먼저 꽂을때
        total += -(neg[0])
        neg = neg[M:]
    else:
        total += pos[-1]
        pos = pos[:len(pos) - M]

# 나머지 책 꽂기
total += 2 * (-sum(neg[0::M]) + sum(pos[::-M]))

print(total)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 12904번 A와 B]]></title>
            <link>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-12904%EB%B2%88-A%EC%99%80-B</link>
            <guid>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-12904%EB%B2%88-A%EC%99%80-B</guid>
            <pubDate>Mon, 11 Jul 2022 12:06:36 GMT</pubDate>
            <description><![CDATA[<ul>
<li>유형: 그리디</li>
<li>풀이방법:
T -&gt; S 로 돌아가는 방법을 생각.(발상의 전환이 필요했다..)</li>
</ul>
<pre><code class="language-python">import sys
sys.stdin = open(&#39;input.txt&#39;, &#39;r&#39;)

S = input()
T = input()

s_len = len(S)
t_len = len(T)

while s_len &lt; t_len:
    if T[-1] == &#39;A&#39;:
        T = T[:-1]
    else:
        T = T[:-1][::-1]
    t_len -= 1

if S == T:
    print(1)
else:
    print(0)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[앞으로의 코테 준비...]]></title>
            <link>https://velog.io/@lea-hwang/%EC%95%9E%EC%9C%BC%EB%A1%9C%EC%9D%98-%EC%BD%94%ED%85%8C-%EC%A4%80%EB%B9%84</link>
            <guid>https://velog.io/@lea-hwang/%EC%95%9E%EC%9C%BC%EB%A1%9C%EC%9D%98-%EC%BD%94%ED%85%8C-%EC%A4%80%EB%B9%84</guid>
            <pubDate>Sun, 10 Jul 2022 04:13:50 GMT</pubDate>
            <description><![CDATA[<p>앞으로 코테를 어떻게 해야할까에 대해 진지하게 고민이 되었다.
프로젝트를 하면 알고리즘을 따로 공부할 시간이 많이 없을 것 같아서..</p>
<p>코딩 테스트를 통과하기 위해서, 어떻게 하면 좋을까.. 정말 고민을 많이 하다가
유튜브에 있는 나동빈님의 대기업 IT 직군 합격 방법 이었나..?
그 영상을 보고 일단 그리디부터 좀 풀어보기로 했다.</p>
<p>알고를 놓은지 한달이 넘었기 때문에, 일단 너무 무리하지 않도록(어려운 문제 풀다가 또 놓아버리지 않도록...) 쉬운 문제부터 차근차근 시작해보려 한다. 그래서 처음에는 실버부터 다시 시작하기로 했다.</p>
<p>이번주는 실버 5<del>1까지의 문제로 조금 마음을 달래고 간간히 골드 4</del>5 문제를 기웃기웃... 해봐야지..! 블로그에는 매일 푼 문제 중 가장 생각이 많이 필요했던 문제를 올려볼 예정이다.. 꾸준히 또 열심히 해야지..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 2138번 전구와 스위치]]></title>
            <link>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-2138%EB%B2%88-%EC%A0%84%EA%B5%AC%EC%99%80-%EC%8A%A4%EC%9C%84%EC%B9%98</link>
            <guid>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-2138%EB%B2%88-%EC%A0%84%EA%B5%AC%EC%99%80-%EC%8A%A4%EC%9C%84%EC%B9%98</guid>
            <pubDate>Sun, 10 Jul 2022 04:05:06 GMT</pubDate>
            <description><![CDATA[<ul>
<li>유형: 그리디</li>
<li>풀이방법:
첫번째 스위치를 누른다고 가정했을 때, 그렇지 않았을 때 두가지 경우로 나누어서
i-1번째의 전구가 켜져있는지 꺼져있는지 여부를 확인하고 스위치를 누를지 말지를 결정한다.</li>
<li>유의할점:
첫번째 스위치를 누른다고 가정 -&gt; cnt 값을 +1 해주어야 함
첫번째 스위치를 눌렀을 때, 1, 2번 전구를 &#39;켜는 것&#39;이 아닌 &#39;반대로&#39; 하는 것..(처음부터 켜져있을 수 있다는 것을 깜박했다..)</li>
</ul>
<pre><code class="language-python">import sys
sys.stdin = open(&#39;input.txt&#39;, &#39;r&#39;)

N = int(input())
INF = int(1e9)

s1 = list(map(int, input())) # 현재 전구
s2 = s1.copy()
a = list(map(int, input()))

s2[0] = not s2[0] # 첫번째 스위치를 누른다고 가정
s2[1] = not s2[1]

def solution(s, cnt):
    for i in range(1, N):
        if s[i-1] != a[i-1]: # i-1번째 전구가 다를 경우 스위치 누르기
            cnt += 1
            s[i-1] = not s[i-1]
            s[i] = not s[i]
            if i+1 &lt; N:
                s[i+1] = not s[i+1]
    if s[N-1] == a[N-1]:
        return cnt
    return INF


answer = min(solution(s1, 0), solution(s2, 1))

if answer != INF:
    print(answer)
else:
    print(-1)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 12018 - Yonsei TOTO]]></title>
            <link>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-12018-Yonsei-TOTO</link>
            <guid>https://velog.io/@lea-hwang/%EB%B0%B1%EC%A4%80-12018-Yonsei-TOTO</guid>
            <pubDate>Sat, 09 Jul 2022 02:54:49 GMT</pubDate>
            <description><![CDATA[<ul>
<li>유형: 그리디</li>
<li>풀이방법: 각 과목당 필요한 마일리지를 구해 현재 마일리지로 들을 수 있는 과목수를 구한다.</li>
<li>유의할 점: 수강신청 인원이 수강인원보다 적을 경우 1 마일리지로 들을 수 있다.</li>
</ul>
<pre><code class="language-python">
import sys
# sys.stdin = open(&#39;input.txt&#39;, &#39;r&#39;)

input = sys.stdin.readline

n, m = map(int, input().split())  # 과목 수, 마일리지
min_M = [0] * n

for i in range(n):
    P, L = map(int, input().split())  # 각 과목에 신청한 사람 수, 과목의 수강인원
    M = list(map(int, input().split()))  # 넣은 마일리지
    if P &gt;= L:
        M.sort()
        min_M[i] = M[P - L]
    else:
        min_M[i] = 1


min_M.sort()  # 오름차순 정렬

total = 0
cnt = 0
for i in range(n):
    if total + min_M[i] &gt; m:
        break
    total += min_M[i]
    cnt += 1

print(cnt)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SWEA] 1767. [SW Test 샘플문제] 프로세서 연결하기]]></title>
            <link>https://velog.io/@lea-hwang/SWEA-1767.-SW-Test-%EC%83%98%ED%94%8C%EB%AC%B8%EC%A0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%84%9C-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@lea-hwang/SWEA-1767.-SW-Test-%EC%83%98%ED%94%8C%EB%AC%B8%EC%A0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%84%9C-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 25 Jun 2022 14:47:54 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lea-hwang/post/2dc7489f-35da-45c3-9c70-912d89a33ad3/image.png" alt=""></p>
<p><a href="https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV4suNtaXFEDFAUf&amp;categoryId=AV4suNtaXFEDFAUf&amp;categoryType=CODE&amp;&amp;&amp;">SWEA 1767 프로세서 연결하기</a></p>
<ul>
<li>풀이시간: 1시간 34분</li>
<li>시간: 8초</li>
<li>메모리: 힙, 정적 메모리 합쳐서 256MB 이내, 스택 메모리 1MB 이내</li>
</ul>
<h2 id="풀이-방법">풀이 방법</h2>
<ul>
<li>모든 코어를 동, 서, 남, 북 방향에 대해서 연결하면서 최대로 연결할 수 있는 코어의 수 파악</li>
<li>DFS로 접근. 한 코어가 연결되면 그 다음 코어를 연결하는 방식. -&gt; 재귀로 구현</li>
</ul>
<h2 id="함수-설계">함수 설계</h2>
<ol>
<li>solution: 각각의 경우의 수에 대해서 다른 함수들을 추가적으로 실행할 함수. 최대 코어 수 리턴</li>
<li>core_connect_possible: 코어 연결이 가능한지 파악하는 함수</li>
<li>core_connection: 코어를 연결하는 함수</li>
<li>core disconnection: 코어 연결을 해제하는 함수</li>
</ol>
<h2 id="생각해본-것들">생각해본 것들.</h2>
<ol>
<li>가장자리에 있는 모든 코어는 이미 연결되어 있다고 가정하여 미리 제외 -&gt; 안하면 시간 초과 발생</li>
<li>전역 변수로 뺄 수 있는 것들은 그냥 전역변수로 뺄 것...</li>
<li>DFS의 종료조건 잘 생각하기</li>
<li>코어 연결이 불가능할 때, 아니면 일부러 연결하지 않을 때를 고려할 때 for 문 밖으로 빼야함... 그렇지 않으면 모든 포문(동서남북)에서 돌아가게 됨..</li>
</ol>
<h2 id="느낀점">느낀점</h2>
<ul>
<li>DFS 공부 다시 열심히 하자...</li>
<li>항상 모든 코드는 설계대로만 하면 잘 될 거라 생각하지만 수정이 필요하다...ㅠㅠ</li>
</ul>
<pre><code class="language-python">import sys
sys.stdin = open(&#39;1767_input.txt&#39;, &#39;r&#39;)

input = sys.stdin.readline
T = int(input()) # 테스트 케이스 수

mat = []
cores = []
N = 0
C = 0


# 코어를 연결할 수 있는지 여부 파악
def core_connect_possible(i, j, di, dj):
    ni, nj = i, j
    while True:
        ni += di
        nj += dj
        if 0&lt;=ni&lt;N and 0&lt;=nj&lt;N:
            # 해당 mat에 코어나 전선이 있을 때 return False
            if mat[ni][nj]:
                return False
        # 인덱스를 벗어났을 때 return True
        else:
            return True

# i, j에 위치한 코어 di, dj 방면으로 연결
def core_connection(i, j, di, dj):
    ni, nj = i, j
    line_len = 0
    while True:
        ni += di
        nj += dj
        if 0 &lt;= ni &lt; N and 0 &lt;= nj &lt; N:
            mat[ni][nj] = 2
            line_len += 1
        # 인덱스를 벗어났을 때 return 라인값
        else:
            return line_len

# i, j에 위치한 코어 연결 해제
def core_disconnection(i, j, di, dj):
    ni, nj = i + di, j + dj
    while True:
        if 0 &lt;= ni &lt; N and 0 &lt;= nj &lt; N:
            mat[ni][nj] = 0
            ni += di
            nj += dj
        # 인덱스를 벗어났을 때
        else:
            return


# checked_core: 현재까지 확인된 코어의 수
# core: 현재까지 연결된 코어의 수
# line: 현재까지 연결된 라인의 길이
def solution(checked_core, core, line):
    global core_line

    # 갱신 조건
    # 현재까지 연결된 코어의 수가 더 높거나, 더 적은 라인이 연결되었을 때,
    if (core_line[0] &lt; core) or (core_line[0] == core and line &lt; core_line[1]):
        core_line = [core, line]

    # 종료 조건
    # 만약 모든 core를 확인했을 때 return
    if checked_core == C:
        return

    i, j = cores[checked_core] # 현재 코어의 위치
    # DFS로 모든 core의 동서남북 방면에 전선연결해보기
    for di, dj in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
        if core_connect_possible(i, j, di, dj):
            cur_line = core_connection(i, j, di, dj)
            solution(checked_core + 1, core + 1, line + cur_line)
            core_disconnection(i, j, di, dj)

    # 연결이 불가능 혹은 연결하지 않을 때 확인(for문 밖으로 빼야함)
    solution(checked_core + 1, core, line)


for tc in range(1, T+1):
    # 1. 입력값 받기
    N = int(input()) # 멕시노스의 크기 N * N
    mat = [list(map(int, input().split())) for _ in range(N)] # N*N 멕시노스
    core_line = [0, 0]  # 최대 코어 수, 최소 라인 길이
    cores = [] # 코어 위치 정보

    # 2. 해 찾기 전 세팅. - 코어의 위치 저장 및 총 개수 확인
    for i in range(N):
        for j in range(N):
            if mat[i][j]:
                if i == 0 or i == N-1 or j == 0 or j == N-1: # 가장자리에 있는 코어 제외.
                    core_line[0] += 1
                else:
                    cores.append((i, j)) # 코어의 위치 저장
    C = len(cores) # 전체 코어의 수

    # 3. 해 찾기
    solution(0, core_line[0], 0)

    print(f&#39;#{tc} {core_line[1]}&#39;)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[한 학기를 마치며, 그리고 새로운 마음가짐으로,,]]></title>
            <link>https://velog.io/@lea-hwang/%ED%95%9C-%ED%95%99%EA%B8%B0%EB%A5%BC-%EB%A7%88%EC%B9%98%EB%A9%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0%EC%83%88%EB%A1%9C%EC%9A%B4-%EB%A7%88%EC%9D%8C%EA%B0%80%EC%A7%90%EC%9C%BC%EB%A1%9C</link>
            <guid>https://velog.io/@lea-hwang/%ED%95%9C-%ED%95%99%EA%B8%B0%EB%A5%BC-%EB%A7%88%EC%B9%98%EB%A9%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0%EC%83%88%EB%A1%9C%EC%9A%B4-%EB%A7%88%EC%9D%8C%EA%B0%80%EC%A7%90%EC%9C%BC%EB%A1%9C</guid>
            <pubDate>Sat, 25 Jun 2022 09:30:00 GMT</pubDate>
            <description><![CDATA[<p>SSAFY 1학기가 끝나고 어느덧 2학기를 앞두고 있는 시점에서 나태해져 있는 나 자신을 볼 수 있었다.</p>
<p>이러한 나 자신을 바로잡기 위해, 새로운 다짐을 할 겸 글을 작성해보려 한다.</p>
<h2 id="1학기-돌아보기">1학기 돌아보기</h2>
<h3 id="1학기에-이룬-것들">1학기에 이룬 것들!</h3>
<p>먼저 1학기에 이룬 것들을 정리해보자면</p>
<h4 id="1-모의-sw-역량테스트-a-취득">1. (모의) SW 역량테스트 A+ 취득</h4>
<p>합격 문자를 받았었는데... 어디로 간걸까..ㅠㅠㅠ</p>
<h4 id="2-백준-골드-달성">2. 백준 골드 달성</h4>
<p><img src="https://velog.velcdn.com/images/lea-hwang/post/02c9f434-6950-4fd8-b8aa-ea9ca3bd27ee/image.png" alt=""></p>
<h4 id="3-정보처리기사-자격증-취득">3. 정보처리기사 자격증 취득</h4>
<p><img src="https://velog.velcdn.com/images/lea-hwang/post/540acde6-9c05-4c09-9b3f-9333b8fb9d17/image.png" alt=""></p>
<h4 id="4-ssafy-성적우수자-2등">4. SSAFY 성적우수자 2등</h4>
<p>구미 1반 비전공자 반에서 성적우수자 2등을 거머쥘 수 있었다. 나름 뿌듯,,ㅎㅎ</p>
<h4 id="5-ssafy-1학기-최종-프로젝트-1등">5. SSAFY 1학기 최종 프로젝트 1등</h4>
<p>사실 1등할 꺼라 생각을 못했는데 하게 되어서 너무 뿌듯하다..ㅎㅎㅎ 프론트엔드로 참여했는데,, 매일 새벽 네시에 잠들고 8시 반에 일어나는 일상을 살았더니,, 힘들었지만, 너무 재미있었고 배운 것이 많았던 프로젝트! 나중에 꼭 코드리뷰하고 블로그에 정리해봐야지!ㅎㅎ</p>
<h5 id="발표-ppt">발표 PPT</h5>
<p><a href="https://github.com/lea-hwang/oneshot">ONE SHOT</a>
<img src="https://velog.velcdn.com/images/lea-hwang/post/de508b05-fd4a-4d5e-b54d-a1b9c1e57e72/image.png" alt="">
<img src="https://velog.velcdn.com/images/lea-hwang/post/889c1a33-499d-44a8-9608-3c5c5788ce57/image.png" alt="">
<img src="https://velog.velcdn.com/images/lea-hwang/post/7d4be88b-28ec-4cab-ba52-da683915d063/image.png" alt=""></p>
<h4 id="6-이것이-코딩-테스트이다-1회독">6. 이것이 코딩 테스트이다 1회독</h4>
<p>골드스푼(알고리즘 스터디)에서 했던 이코테 1회독! 매주 참여하는 것이 쉽지 않았지만 꾸역꾸역 해가려고 했었던,,ㅠㅠ 이제 다시 열심히 해야지!!
<a href="https://github.com/lea-hwang/TIL/tree/master/%EC%9D%B4%EC%BD%94%ED%85%8C">이것이 코딩 테스트이다 TIL</a></p>
<h4 id="7-토이-프로젝트-오늘의-메뉴">7. 토이 프로젝트, &#39;오늘의 메뉴&#39;</h4>
<p>처음에 Javascript를 좀 더 빨리 배워보고 싶어서, 노마드코더의 &#39;바닐라JS로 크롬 앱 만들기&#39;를 수강해서 기초를 익히고, 그 다음 바로 HTML, CSS, JS 만으로 홈페이지 만들어보자 해서 프로젝트를 하게 되었다. <del>혼자하기엔 항상 걱정이 되어서 사람들을 모아 같이 프로젝트 해보자고 설득했었던...ㅎㅎ</del></p>
<p>오늘 뭘 먹으면 좋을까? 라는 질문을 매일 나 자신에게 물어보는 것을 보며, 이를 해결할 수 있는 홈페이지가 있다면 좋겠다라는 생각에서 시작했던 프로젝트. 
생각보다 시간이 많이 걸려서 쉽지 않았지만, 너무 재밌었다. 프론트 생각보다 재밌구나 했었던 프로젝트.. 또 해봐야지!.
<a href="https://github.com/lea-hwang/today-menu.github.io">오늘의 메뉴 github</a>
<a href="https://lea-hwang.github.io/today-menu.github.io/">오늘의 메뉴 홈페이지</a>
<img src="https://velog.velcdn.com/images/lea-hwang/post/1dfc1a87-531c-4975-a8f8-80d3d1cf5c4c/image.png" alt=""></p>
<h3 id="이루지-못한-것들">이루지 못한 것들</h3>
<h4 id="1-sqld-자격증-취득">1. sqld 자격증 취득</h4>
<p>SSAFY 최종 프로젝트와 sqld 자격증 공부를 동시에 할 수 있다고 생각한 과거의 나,,, 혼내야한다.. 진짜..ㅠㅠ 절대 못해요...ㅠㅠㅠ</p>
<h4 id="2-백준-플래티넘-달성">2. 백준 플래티넘 달성..</h4>
<p>초반에는 열심히 하다가 나중에 나태해져서 못했던 플래티넘... 올해 내에 플래티넘으로 다시 도전해야지! 골3에서 올라가려면 얼마나 걸리려나,,!</p>
<h4 id="3-블로그--github--노션-관리">3. 블로그 / github / 노션 관리</h4>
<p>후... 기록을 항상 힘들어하는 나 자신.. 다시 문서 작성하는 법을 터득할 때까지 노력해야지..ㅠㅠㅠ 노션 많이 써봐야겠다.. md,,,파일도 화이팅...!!</p>
<h4 id="4-포트폴리오-정리-및-취업-준비">4. 포트폴리오 정리 및 취업 준비</h4>
<p>1학기 때 취업 준비할 시간 없이 너무 바빴다.. 핑계려나,, 그렇지만 정말 바쁘긴했는걸..ㅠㅠ 수업 따라가랴, 스터디하랴, 프로젝트하랴,, 너무 정신이 없었다..ㅠㅠ 하루에 모든걸 몰아서 하려고 하지말고 조금씩 조금씩 정리하는 습관을 들여야지..</p>
<h4 id="한학기를-마치며-그리고-다시-시작하기-위해">한학기를 마치며, 그리고 다시 시작하기 위해..,</h4>
<p>생각보다 이룬 것도 많지만, 못 이룬 것들도 많아서 너무 아쉬웠다. 점점 나태해져 가는 나 자신을 보며 스스로에 대한 실망도 커져갔다. 이런 나를 바로잡기 위해 계획을 수립해보려한다.</p>
<h3 id="2학기-목표">2학기 목표</h3>
<h4 id="1-알고리즘--코테준비">1. 알고리즘 + 코테준비</h4>
<ul>
<li><p>백준 플래티넘 달성(solvedac class 5 달성)
원래의 1학기 목표가 골드이긴 했는데, 골드 달성 이후로 나태해진 모습을 보며, 마음을 다잡아야겠다는 생각이 들었다.. 최소 실버 4문제 이상의 문제들을 꾸준히 풀어야지.. Git 잔디와 더불어 백준 잔디도 열심히 심어야지.</p>
</li>
<li><p>이것이 코딩테스트이다 2회독
2회독을 할 생각이 없었는데, 새로운 것을 공부하기보다는 이전에 배웠던 것을 복습해서 머릿속에 확실히 개념을 잡고 가야겠다는 생각이 들어서 2회독을 하려고 한다. 1회독때는 가볍게 해당 개념을 이해했다면, 2회독 때는 꼼꼼히 정리하면서 배웠던 개념을 복습하고 풀었던 문제들을 다시 풀어보며 해당 코드의 템플릿을 다시 익히는 연습들을 할 것이다.</p>
</li>
</ul>
<h4 id="2-cs">2. CS</h4>
<ul>
<li>컴퓨터구조 / 운영체제 / 네트워크
아직 CS 공부의 방향성을 잡지 못했지만, 다른 분들과 스터디를 만들어서 꾸준히 공부해보려고 한다. CS에는 너무 무지한 터라 쉽지는 않겠지만, 차근차근 하다보면 많이 늘어있는 내 자신을 볼 수 있지 않을까..? 일단 강의 or 요약본들을 보면 기본적인 것부터 차근차근 공부해봐야겠다.</li>
</ul>
<h4 id="3기록-관리">3.기록 관리</h4>
<ul>
<li>블로그
블로그에는 주로 프로젝트를 하면서 고민했던 흔적들을 남겨보려고 한다. 이전에 했던 프로젝트들 다시 보면서 내가 배웠던 것들을 정리하고 앞으로의 프로젝트를 하는 과정에서 내가 배웠던 것들을 차근차근 정리해봐야지.<ul>
<li>Github
잔디를 꽉꽉 채우겠다던 나. ㅠㅠ 알고리즘 문제를 풀 시간이 줄어들자 텅텅 비어버린 잔디밭,, 또 제주도에 한번 갔다오고 긴 방학을 즐기다보니... 다시 마음을 다 잡고 시작해야지! 매일 보단 <strong>일주일 5푸시!</strong>를 목표로! 매일 매일은 너무 힘드니까, 나 자신에게 집중과 휴식을!</li>
<li>Notion
일정표와 계획표를 잘 작성하지 못하는 나. 이전 프로젝트를 하며 미현언니가 작성하는 것을 보며 많은 것을 깨달았다.. 나 열심히 노션 써봐야지..ㅠㅠ</li>
</ul>
</li>
</ul>
<h4 id="4-프로젝트">4. 프로젝트</h4>
<p>이번 2학기때 프로젝트를 3개 할텐데,, 잘 할 수 있을까.. 너무 걱정이 된다.. 그래도 열심히 해야지..!!!! 개인 프로젝트도 꼭 하고 싶었는데.. 시간이 있을까.. 싶다.. 일정 잘 짜봐야겠어..ㅠㅠ</p>
<h4 id="5-리액트-공부">5. 리액트 공부</h4>
<p>프론트로 전향하기로 한 만큼 자바스크립트는 확실히 공부하고 리액트도 확실하게 공부하는 걸로..ㅠㅠ 잘 할 수 있을까 걱정이 되지만 일정 확실히 짜봐야지. 생활코딩 리액트 먼저 공부하고 벨로퍼트 공부하고 노마드코더 강의 들어보는 걸루,,!</p>
<h4 id="6-취업준비">6. 취업준비</h4>
<p>제일 중요한 취업준비..!!! 항상 나만 제일 모르는 취업 현황. 열심히 알아보고 찾아봐야지.. 주는 밥만 그만 먹고 상차리기 도전해야겠다.</p>
<ol>
<li>가고싶은 기업 리스트 정리</li>
<li>각 기업별 취업 공고 정리</li>
</ol>
<ul>
<li>스펙 정리(프레임워크, 언어, 포지션)</li>
<li>연봉 및 복지 혜택 정리</li>
<li>근무 지역 정리</li>
</ul>
<ol start="3">
<li>해당 취업 공고에 따른 내가 해야할 것들 정리</li>
<li>포트폴리오 작성</li>
<li>자기소개서 준비</li>
<li>인적성, 면접 준비</li>
</ol>
<h4 id="7-sqld-자격증-및-sql-공부">7. sqld 자격증 및 sql 공부</h4>
<p>프로그래머스에서 코테를 칠 때마다 종종 보이는 SQL 코테,, 잘 준비해봐야지.... 일정을 잘 짜봐야겠다..ㅠㅠ 시험이 언제더라...(9/4 11/5 할 수 있을까..?) 2학기 프로젝트 기간 보면서 준비해봐야지..!</p>
<p>이렇게 작성하면서도 정말 계획해야할 것들이 너무 많다라는 생각이 들었다. 후하.. 작성했던 내용들을 조금씩 수정해보면서 꾸준히 준비해야지! 남은 올해 화이팅!!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Django] 프로젝트 시작하기]]></title>
            <link>https://velog.io/@lea-hwang/Django-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%ED%8B%80-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@lea-hwang/Django-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%ED%8B%80-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Sun, 10 Apr 2022 13:29:25 GMT</pubDate>
            <description><![CDATA[<p>기본적인 게시판을 만든다고 가정.
프로젝트 이름은 <code>board</code>, 애플리케이션 이름은 <code>posts</code>로 설정.</p>
<h3 id="파일-구조">파일 구조</h3>
<p><img src="https://velog.velcdn.com/images/lea-hwang/post/98ee3d29-7596-40d4-820c-0a7df6b8c0d6/image.png" alt=""></p>
<h3 id="1--가상환경-생성-및-실행">1.  가상환경 생성 및 실행</h3>
<pre><code class="language-cmd">$ python -m venv venv
$ source venv/Scripts/activate</code></pre>
<p>개발 전 가상환경을 먼저 생성해주고 실행시킨다.</p>
<h3 id="2-requirementstxt-패키지-설치-or-장고패키지-설치">2. requirements.txt 패키지 설치 or 장고패키지 설치</h3>
<pre><code class="language-bash">$ pip list
$ pip install -r requirements.txt</code></pre>
<p>만약 requirements.txt에 설치할 패키지가 적혀 있다면, 해당 패키지들을 설치해주자.</p>
<pre><code class="language-bash">$ pip install django==***
$ pip freeze &gt; requirements.txt</code></pre>
<p>그렇지 않다면(이제 처음 프로젝트 생성이라면), 장고 패키지를 설치해주고 requirements.txt를 생성한다.</p>
<h3 id="3-장고-프고젝트-생성">3. 장고 프고젝트 생성</h3>
<pre><code class="language-bash">$ django-admin startproject board .</code></pre>
<p><code>board</code>라는 이름으로 프로젝트를 생성한다.</p>
<h3 id="4-장고-앱-생성-및-settingspy-등록">4. 장고 앱 생성 및 settings.py 등록</h3>
<pre><code class="language-bash">$ python manage.py startapp posts</code></pre>
<p><code>posts</code>라는 이름을 가진 장고 어플리케이션을 생성한다.</p>
<pre><code class="language-python"># board/settings.py
INSTALLED_APPS = [
    &#39;posts&#39;,
      ...
]</code></pre>
<p>해당 어플리케이션을 board/settings.py 파일의 INSTALLED_APPS에 추가한다.
<strong>앱을 생성하고 등록해야한다. 주의하자.</strong>
앱이름은 주로 복수형으로 작성한다고 한다.</p>
<h3 id="5-url-분리">5. url 분리</h3>
<p><code>posts/</code>로 시작하는 모든 url을 따로 분리하기 위해 posts/urls.py 파일을 생성해서 작성해준다.</p>
<pre><code class="language-python"># board/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path(&#39;admin/&#39;, admin.site.urls),
    path(&#39;posts/&#39;, include(&#39;posts.urls&#39;)),
]</code></pre>
<p>include를 이용하여 posts/urls.py에 적힌 url들을 포함시킬 수 있다. 이를 통해 각 어플리케이션 혹은 기능별로 url을 관리할 수 있다.</p>
<pre><code class="language-python"># posts/urls.py
from django.urls import path
from . import views

app_name = &#39;posts&#39;
urlpatterns = [
    ...
]</code></pre>
<p>참고: <a href="https://docs.djangoproject.com/en/4.0/topics/http/urls/#including-other-urlconfs-1">https://docs.djangoproject.com/en/4.0/topics/http/urls/#including-other-urlconfs-1</a></p>
<h3 id="6-model-생성-및-등록">6. model 생성 및 등록</h3>
<pre><code class="language-python"># posts/models.py
from django.db import models

# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=20)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)</code></pre>
<p>게시글마다 데이터를 저장해주기 위해 Post 라는 모델을 생성한다.</p>
<ul>
<li>CharField는 max_length를 꼭 지정해주어야 한다.</li>
<li>auto_now_add는 해당 인스턴스가 생성될 때의 시간을 자동으로 저장한다.</li>
<li>auto_now는 해당 인스턴스가 수정될 때의 시간을 자동으로 저장한다.</li>
</ul>
<pre><code class="language-bash">$ python manage.py makemigrations
$ python manage.py migrate</code></pre>
<p>model 생성 정보를 데이터베이스에 반영하기 위해 migrate 한다.</p>
<hr>
<h4 id="좀-더-공부하고-싶은-것">좀 더 공부하고 싶은 것?</h4>
<ul>
<li>가상환경을 왜 만들어야할까?</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>