<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>newn.log</title>
        <link>https://velog.io/</link>
        <description>제품을 통해 가치를 전달합니다.</description>
        <lastBuildDate>Mon, 29 Dec 2025 13:03:56 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>newn.log</title>
            <url>https://velog.velcdn.com/images/c-jeongyyun/profile/6800d088-ebd7-4157-a624-ce3a69884ff7/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. newn.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/c-jeongyyun" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[SolveSQL 어드밴트 캘린더 완주!🎅🏻(Advent of SQL 2025, SolveSQL)]]></title>
            <link>https://velog.io/@c-jeongyyun/SolveSQL-%EC%96%B4%EB%93%9C%EB%B0%B4%ED%8A%B8-%EC%BA%98%EB%A6%B0%EB%8D%94-%EC%99%84%EC%A3%BCAdvent-of-SQL-2025-SolveSQL</link>
            <guid>https://velog.io/@c-jeongyyun/SolveSQL-%EC%96%B4%EB%93%9C%EB%B0%B4%ED%8A%B8-%EC%BA%98%EB%A6%B0%EB%8D%94-%EC%99%84%EC%A3%BCAdvent-of-SQL-2025-SolveSQL</guid>
            <pubDate>Mon, 29 Dec 2025 13:03:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/afcbd396-c2f2-4734-a94c-46f9309f9579/image.png" alt=""></p>
<p>좀 늦었지만 작성해보는 후기ㅎㅎ</p>
<p>Advent of SQL 2025는 solveSQL에서 진행하는 이벤트로, 12월 1일 부터 크리스마스까지 매일 하나의 SQL을 문제를 푸는 것으로 구성되어있다.</p>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/cfa3a534-f40c-41ea-b8a6-5bb9d2e5b223/image.png" alt="등급표"></p>
<p>위와 같이 어떤 시점에 문제를 풀었느냐에 따라서 받을 수 있는 뱃지가 나뉘어지는데, 나는 12월 1일부터 매일매일 시간안에 모든 문제를 풀어 Advent of 2025 뱃지를 받았다.</p>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/7fddcbc0-7cb1-4e24-bdaa-e36e7c54f6ea/image.png" alt=""></p>
<p>Can you see this?!</p>
<p>38명 중 한명이라니 뿌듯하군. (야호~)</p>
<p>회사 다니면서 DB 마이그레이션할 때 SQL를 쓰긴 했지만,
자주 쓰진 않았어서 문법이 가물가물 했었는데 이번에 문제들을 풀면서 많이 감이 끌어올려진 것 같다. 특히나 윈도우 함수를 활용하는 것에 많이 익숙해진 것이 가장 큰 수확이라고 생각한다!</p>
<p>한편으로는 문제를 풀면서, &#39;문제 상황에 대한 해결책은 AI가 더 잘하긴 할텐데, 의미가 있는 활동일까?&#39; 라는 생각도 들었다. 이 어드벤트 캘린더를 완주한 지금도 생각은 동일하긴 하다. AI가 나보다 더 빨리 잘 풀 수 있을 것 같다.</p>
<p>그렇다면 이 활동의 의의가 뭐였을까?</p>
<br/>

<h2 id="의의">의의</h2>
<p><strong>1. 알아야 판단할 수 있다.</strong></p>
<p>나는 미래의 개발자 핵심 역할 중 하나가 판단이라고 생각한다. 누군가 생산한 코드가 도메인과 구조에 장기적으로 적합한지를 최종적으로 책임지고 결정해야하는 사람이 있어야 한다고 생각하고, 그게 전문지식을 보유한 개발자가 될 것이라고 생각한다. 즉, 판단을 위해서는 전문지식이 필요하며 그에 익숙한 사람이어야 한다. 그러한 측면에서 이번 활동은 SQL에 좀더 노출되고 익숙해지는 시간이었다고 생각한다. 간단히 말하면 공부의 일환이었다는 것~ </p>
<br/>

<p><strong>2. 루틴 시작의 트리거</strong></p>
<p>나를 움직이는 원동력은 루틴이다. 루틴을 시작하기만 하면, 나머지는 일사천리로 진행할 수 있다. 그러한 측면에서, 이 활동은 큰 부담도 없고, 문제를 풀었을 때 성취감이 있기 때문에, 카페에 앉아 가장 먼저 시작할 수 있는 일이 되었다. 내 루틴을 시작하는 요긴한 트리거로 아주 잘 작동한 셈이다.</p>
<br/>



<h2 id="마무리하며">마무리하며</h2>
<p>2025년 연말에 가벼운 마음으로 하기 좋았던 활동이었다ㅎㅎ
무사히 완주한 나 자신에게 박수!👏
2026년에는 더 많은 도전들을 해나갈 예정인데, 새로운 성취를 위한 좋은 시작점인 것 같다. 
기대되는구만. 
남은 연말에는 회고하는 시간과 함께 새로운 목표를 가지고 돌아오겠다. </p>
<p>그럼 이만<del>~</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL) date -> 요일로 변환 시, TO_CHAR 함수에서의 주의점]]></title>
            <link>https://velog.io/@c-jeongyyun/SQL-date-%EC%9A%94%EC%9D%BC%EB%A1%9C-%EB%B3%80%ED%99%98-%EC%8B%9C-TOCHAR-%ED%95%A8%EC%88%98%EC%97%90%EC%84%9C%EC%9D%98-%EC%A3%BC%EC%9D%98%EC%A0%90</link>
            <guid>https://velog.io/@c-jeongyyun/SQL-date-%EC%9A%94%EC%9D%BC%EB%A1%9C-%EB%B3%80%ED%99%98-%EC%8B%9C-TOCHAR-%ED%95%A8%EC%88%98%EC%97%90%EC%84%9C%EC%9D%98-%EC%A3%BC%EC%9D%98%EC%A0%90</guid>
            <pubDate>Mon, 22 Dec 2025 03:59:27 GMT</pubDate>
            <description><![CDATA[<p>SQL을 연습할 겸, solvesql에서 진행하는 <a href="https://solvesql.com/collections/advent-of-sql-2025/">Advent of SQL 2025 🎅</a> 에 참여 중이다.</p>
<p><a href="https://solvesql.com/problems/cumulative-orders/">12월 22일자 문제</a>를 푸는 도중 알게 된 것에 대한 간단 공유.</p>
<h1 id="상황">상황</h1>
<p>datetime 타입의 칼럼을 요일로 변환해야 했다.</p>
<h1 id="풀이방법">풀이방법</h1>
<pre><code class="language-sql">TO_CHAR(칼럼명, &#39;Day&#39;)</code></pre>
<p>를 사용해서 변환. </p>
<h1 id="문제상황">문제상황</h1>
<img src="https://velog.velcdn.com/images/c-jeongyyun/post/5e9cb699-9545-4572-b0d4-dcbd6a81feb1/image.png" width=500 />

<ul>
<li>제출: Thursday</li>
<li>정답: Thursday</li>
</ul>
<p>??????? 
뭘 잘못한거지??????????</p>
<h1 id="원인">원인</h1>
<p>PostgreSQL의 <code>TO_CHAR</code> 함수 스펙을 제대로 알지 못해 발생한 문제다.</p>
<p><a href="https://www.postgresql.org/docs/current/functions-formatting.html">TO_CHAR 함수 스펙</a>을 확인해보자.
<img src="https://velog.velcdn.com/images/c-jeongyyun/post/a9c75620-36f8-48ea-9112-e64cc862d6fb/image.png" alt=""></p>
<p>9char을 맞추기 위해 공백 패딩이 들어가있다고 한다.
오류 문구를 다시 보니 <code>Thursday</code> 가 아닌 <code>Thursday</code> 임을 확인할 수 있었다.</p>
<h1 id="해결">해결</h1>
<p><code>TRIM</code> 함수쓰기! </p>
<pre><code class="language-sql">TRIM(TO_CHAR(칼럼명, &#39;Day&#39;))</code></pre>
<p><code>TO_CHAR(칼럼명, &#39;FMDay&#39;)</code>를 쓰면 공백이 없는 요일명을 반환하긴하나, 이는 PostgreSQL전용 기능이므로, 범용성을 고려하면 TRIM을 사용하는게 더 좋다.</p>
<h1 id="번외">번외</h1>
<p><code>TO_CHAR(칼럼명, &#39;Day&#39;)</code>는 왜 공백 포함하여 9자를 맞출까?</p>
<h3 id="1-왜-9자">1. 왜 9자?</h3>
<p>Wednesday 가 가장 긴 요일명인데, 이게 9자여서.</p>
<h3 id="2공백을-왜-넣을까">2.공백을 왜 넣을까?</h3>
<p>보고서, 터미널 UI 등으로 출력 시 정렬되어보이기 위함.</p>
<p><code>TO_CHAR</code> 함수의 의도가 &#39;데이터 추출&#39;보다는 &#39;출력 포맷 맞추기&#39;인 것으로 보인다. 참고로 PostgreSQL외의 다른 DBMS도 동일하게 공백포함하여 출력된다고 한다.</p>
<hr>
<p>오랜만에 이런 함수 스펙 관련된 이슈를 마주한듯하다. 코딩테스트 준비를 하다보면 사소해보이지만 중요한 지식공백을 발견할 수 있어서 참 좋다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Batch INSERT 문과 COPY 문의 성능차이]]></title>
            <link>https://velog.io/@c-jeongyyun/Batch-INSERT-%EB%AC%B8%EA%B3%BC-COPY-%EB%AC%B8%EC%9D%98-%EC%84%B1%EB%8A%A5%EC%B0%A8%EC%9D%B4-jc8vi93v</link>
            <guid>https://velog.io/@c-jeongyyun/Batch-INSERT-%EB%AC%B8%EA%B3%BC-COPY-%EB%AC%B8%EC%9D%98-%EC%84%B1%EB%8A%A5%EC%B0%A8%EC%9D%B4-jc8vi93v</guid>
            <pubDate>Thu, 11 Dec 2025 02:14:14 GMT</pubDate>
            <description><![CDATA[<h1 id="배경">배경</h1>
<p>회사에서 한달치의 엑셀 데이터를 한번에 업로드하는 기능을 구현하였다.</p>
<p>초기에는 Batch INSERT 방식을 통해 데이터를 삽입하였다. 하나의 SQL 문으로 여러행을 삽입할 수 있었고 초기에는 충분히 빠르게 작동했었다.</p>
<p>그런데 해당 서비스 특성 상, 한달치 데이터의 양이 점진적으로 늘어나는 구조였고, 점점 처리속도가 느려졌다.</p>
<p>검색을 통해, 속도 저하의 원인이 SQL 문 실행 시 파싱에 대한 오버헤드임을 파악하였고, </p>
<p>파싱 오버헤드가 없는 Postgres의 COPY 로 대체하여 약 140%로 처리 속도를 감축하였다. (4000개 데이터 기준)</p>
<p>이번 글에서는 해당 문제 해결 과정에서 학습한 내용들을 정리하고자 한다.</p>
<br/>

<h1 id="개요">개요</h1>
<p>우선 Batch INSERT 문과 COPY문에 대해 간단한 설명을 하고 넘어가겠다.</p>
<br/>

<h2 id="batch-insert문">Batch INSERT문</h2>
<p><code>INSERT INTO … VALUES …</code>  의 형식을 갖추고 있다.</p>
<p> values 절에 여러 개의 행 데이터를 넣으면, 여러개의 행을 한번에 삽입할 수 있다.</p>
 <br/>

<h2 id="copy문">COPY문</h2>
<p>PostgreSQL 전용 기능으로, 대용량 데이터를 한번에 처리할 때 사용한다.</p>
<p>파일이나 스트림에서 데이터를 불러와, 테이블에 삽입하거나 테이블의 데이터를 파일로 내보낼 때 사용된다.</p>
<blockquote>
<p>테이블 삽입 예시</p>
</blockquote>
<pre><code class="language-sql">COPY employees (employee_id, name, department_id, hire_date)
FROM &#39;/tmp/data.csv&#39; 
DELIMITER &#39;,&#39; 
CSV HEADER;</code></pre>
<p>참고</p>
<ul>
<li><code>DELIMITER ’,‘</code> : 필드의 구분자로 <code>,</code>를 쓰겠다는 뜻</li>
<li><code>CSV</code> : 파일형식이 CSV임을 나타냄.</li>
<li><code>HEADER</code> : 맨 첫줄은 필드가 아닌 헤더임으로, 첫줄을 읽지 않도록 설정.</li>
</ul>
<p>또는</p>
<pre><code class="language-sql">COPY my_table (col1, col2) FROM STDIN WITH (FORMAT CSV);</code></pre>
<blockquote>
<p>테이블을 파일로 내보내기 예시</p>
</blockquote>
<pre><code class="language-sql">COPY employees 
TO &#39;/employees_backup.txt&#39;
WITH (DELIMITER E&#39;\t&#39;);</code></pre>
<p>참고</p>
<ul>
<li><code>WITH (DELIMITER E&#39;\t&#39;)</code> : 필드간의 구분은 <code>\t</code> (탭) 으로 하겠다는 뜻</li>
</ul>
<p>지금은 COPY와 INSERT 문을 비교할 것이기 때문에, 테이블 삽입에 대한 내용만 다룰 것이다.</p>
<br/>

<h1 id="비교-실험">비교 실험</h1>
<p>대용량 데이터 처리 시, Batch INSERT문보다 COPY문이 더 빠른 속도를 보인다.</p>
<p>실험을 통해 속도 차이를 확인해보자.</p>
<p>실험 내용은 간단하다.</p>
<p>같은 개수의 데이터를, Batch INSERT로 삽입했을 때의 시간과 </p>
<p>COPY문으로 삽입하였을 때의 시간을 비교한다.</p>
<p>코드는 아래와 같다.</p>
<blockquote>
<p>코드</p>
</blockquote>
<pre><code class="language-python">import psycopg2
import time
from io import StringIO

# 1. DB 연결 설정
conn = psycopg2.connect(
    host=&quot;127.0.0.1&quot;,
    database=&quot;pg-test&quot;,
    user=&quot;jeongyun&quot;,
    password=&quot;jeongyun&quot;,
    port=&quot;5434&quot;
)

# 테스트 데이터 생성 함수 (5,000개)
def generate_data(num_rows):
    data = []
    for i in range(1, num_rows + 1):
        data.append({
            &#39;value1&#39;: f&#39;TestValue_{i}&#39;,
            &#39;value2&#39;: i * 10
        })
    return data

NUM_ROWS = 5000 # 10,000개, 50,000개 바꿔가며 테스트
test_data = generate_data(NUM_ROWS)

# --- 1. 배치 INSERT 테스트 ---
def test_batch_insert(data, connection):
    with connection.cursor() as cur:
        # 트랜잭션 시작
        cur.execute(&quot;BEGIN;&quot;) 

        # 튜플 리스트로 변환
        insert_values = [(item[&#39;value1&#39;], item[&#39;value2&#39;]) for item in data]

        # VALUES (...), (...), (...) 형태의 배치 SQL 생성
        placeholders = &#39;, &#39;.join([&#39;%s&#39;] * len(insert_values[0]))
        query = f&quot;INSERT INTO test_data (value1, value2) VALUES ({placeholders})&quot;

        # executemany를 사용하여 내부적으로 배치 INSERT를 시도 (드라이버 최적화)
        start_time = time.time()
        cur.executemany(query, insert_values)
        end_time = time.time()

        cur.execute(&quot;COMMIT;&quot;)
    return end_time - start_time

# --- 2. COPY FROM STDIN 테스트 ---
def test_copy(data, connection):
    with connection.cursor() as cur:
        # 1. 데이터 문자열 생성 (CSV 형태)
        csv_data = StringIO()
        for item in data:
            # COPY는 필드 순서와 정확히 일치하는 문자열이 필요
            csv_data.write(f&quot;{item[&#39;value1&#39;]},{item[&#39;value2&#39;]}\n&quot;)
        csv_data.seek(0)

        # 2. COPY 실행
        start_time = time.time()
        cur.copy_from(
            csv_data, 
            &#39;test_data&#39;, 
            columns=(&#39;value1&#39;, &#39;value2&#39;),
            sep=&#39;,&#39;
        )
        end_time = time.time()

    connection.commit()
    return end_time - start_time

# --- 테스트 실행 및 결과 출력 ---

# 테이블 초기화
with conn.cursor() as cur:
    cur.execute(&quot;TRUNCATE TABLE test_data RESTART IDENTITY;&quot;)
conn.commit()

# 배치 INSERT 실행
batch_time = test_batch_insert(test_data, conn)

# 테이블 초기화
with conn.cursor() as cur:
    cur.execute(&quot;TRUNCATE TABLE test_data RESTART IDENTITY;&quot;)
conn.commit()

# COPY 실행
copy_time = test_copy(test_data, conn)

print(f&quot;--- {NUM_ROWS}개 데이터 로드 결과 ---&quot;)
print(f&quot;1. 배치 INSERT 시간: {batch_time:.4f} 초&quot;)
print(f&quot;2. COPY FROM STDIN 시간: {copy_time:.4f} 초&quot;)
print(f&quot;\nCOPY가 배치 INSERT보다 약 {(batch_time / copy_time):.2f}배 빠릅니다.&quot;)

conn.close()</code></pre>
<blockquote>
<p>결과</p>
</blockquote>
<img src="https://velog.velcdn.com/images/c-jeongyyun/post/e45c7401-333e-4cc7-9dc5-270eadd3d347/image.png" width="400"/>

<p>5,000-10,000-50,000-30,000-20,000-40,000 순</p>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/f74fadf6-5608-494a-8ad7-aa35e3683ae9/image.png" alt="output"></p>
<table>
<thead>
<tr>
<th>데이터 개수 (rows)</th>
<th>배치 INSERT 시간 (초)</th>
<th>COPY FROM STDIN 시간 (초)</th>
<th>속도 비율 (COPY/INSERT, 배)</th>
</tr>
</thead>
<tbody><tr>
<td>5,000</td>
<td>1.6004</td>
<td>0.0085</td>
<td>187.73</td>
</tr>
<tr>
<td>10,000</td>
<td>3.3135</td>
<td>0.0127</td>
<td>261.81</td>
</tr>
<tr>
<td>20,000</td>
<td>6.8093</td>
<td>0.0211</td>
<td>323.36</td>
</tr>
<tr>
<td>30,000</td>
<td>10.1457</td>
<td>0.0300</td>
<td>337.97</td>
</tr>
<tr>
<td>40,000</td>
<td>13.3870</td>
<td>0.0391</td>
<td>341.95</td>
</tr>
<tr>
<td>50,000</td>
<td>16.7406</td>
<td>0.0477</td>
<td>350.88</td>
</tr>
</tbody></table>
<p>INSERT 문과, COPY 문 모두 데이터 개수에 비례하게 속도가 증가하긴 하나, 증가폭은 INSERT 문이 현격히 높은 것을 알 수 있다.</p>
<p>둘다 하나의 SQL인데, 왜 COPY가 더 빠를까?</p>
<p>그 이유를 알기 위해서는 SQL의 실행과정을 알아야 한다.</p>
<br/>

<h1 id="해석">해석</h1>
<blockquote>
<p><strong>SQL 문의 실행과정</strong></p>
</blockquote>
<p>여타 언어와 같이, SQL도 결국 일종의 명령어다.</p>
<p>명령어는 해석이 되어야 한다.</p>
<p>SQL은 아래와 같이 네 단계를 거쳐 해석된다. </p>
<ol>
<li>파싱 단계<ul>
<li>SQL문을 토큰 단위(ex. <code>SELECT</code>, <code>*</code>,  <code>FROM</code>, <code>table_name</code> 등)로 자르는 Lexing 단계를 거쳐,</li>
<li>토큰들을 조합하여 문법에 맞는지 확인 후, Parse Tree를 만든다.</li>
</ul>
</li>
<li>분석 단계 <ul>
<li>의미 확인 : SQL 문에서 사용된 테이블명, 함수명 등이 실제로 시스템 상에 존재하는지 확인하고,</li>
<li>권한 확인 : 해당 명령어를 사용할 수 있는 권한이 있는지를 확인하며,</li>
<li>쿼리 정규화 : 테이블 명을 DB 내부 id로 대체하는 등의 작업을 하여 parse tree → query tree 로 변환한다.</li>
</ul>
</li>
<li>플래닝 단계<ul>
<li>옵티마이저 실행: 인덱스 유무, 통계 정보 등을 고려하여 가장 비용이 적게 드는 Execution Plan을 생성한다.</li>
</ul>
</li>
<li>실행 단계<ul>
<li>플래닝 단계에서 생성한 Execution Plan대로 실행한다.</li>
</ul>
</li>
</ol>
<p>Batch INSERT 문의 경우, SQL문 자체가 굉장히 길어진다. </p>
<p>5,000개를 넣는다고 하면 <code>VALUES</code> 절 다음에 5,000개의 행에 대한 데이터 내용이 들어갈 것이고, </p>
<p>50,000개를 넣는다고 하면 <code>VALUES</code> 절 다음에 50,000개의 행에 대한 데이터 내용이 들어갈 것이다.</p>
<p>그말인 즉슨, INSERT 문을 사용할 경우, 데이터가 늘어날수록 데이터베이스 엔진이 파싱해야할 SQL양도 계속 늘어난다는 뜻이다.</p>
<p>반면, COPY의 경우, SQL 문은 데이터 개수와 관계없이</p>
<p><code>COPY test_data (value1, value2) FROM STDIN WITH (FORMAT CSV);</code></p>
<p>으로 고정이다.</p>
<p>데이터가 50,000개든 5,000,000개든 SQL 문 길이는 늘어나지 않는다는 말이다.</p>
<p>그렇기 때문에, COPY 문을 사용할 경우 SQL문 파싱에 드는 속도는 항상 동일하며, 데이터 양에 따라 데이터 스트리밍 시간만 변동되는 것이다. </p>
<br/>

<h1 id="정리">정리</h1>
<p>이번 글에서는 PostgreSQL에서 대용량 데이터를 삽입할 때 <code>Batch INSERT</code>와 <code>COPY</code> 방식 간의 성능 차이를 확인하고, 그 원인에 대해서 분석해보았다.</p>
<p>두 방식 모두 대량의 데이터를 저장하나,</p>
<p> <code>Batch INSERT</code>는 데이터가 많아질수록 SQL 문이 길어져, SQL 파싱에 많은 시간을 소요하는 반면, </p>
<p> <code>COPY</code>는 SQL 문이 고정된 형태로 유지되며 내부적으로 스트리밍 방식으로 데이터를 처리하기 때문에 SQL 파싱에 대한 오버헤드가 거의 없었다. </p>
<p>각 방식의 내부 동작 원리를 이해해야, 데이터 특성과 서비스 구조에 가장 적합한 접근 방식을 선택할 수 있다. </p>
<p>결국 핵심은 ‘되느냐’ 가 아니라 ‘왜 되느냐’ 임을 다시 한번 느낀다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[남의 삽질로그] iframe으로 MFE 구축 시 인증 API 반복호출 이슈]]></title>
            <link>https://velog.io/@c-jeongyyun/%EB%82%A8%EC%9D%98-%EC%82%BD%EC%A7%88%EB%A1%9C%EA%B7%B8-iframe%EC%9C%BC%EB%A1%9C-MFE-%EA%B5%AC%EC%B6%95-%EC%8B%9C-%EC%9D%B8%EC%A6%9D-API-%EB%B0%98%EB%B3%B5%ED%98%B8%EC%B6%9C-%EC%9D%B4%EC%8A%88</link>
            <guid>https://velog.io/@c-jeongyyun/%EB%82%A8%EC%9D%98-%EC%82%BD%EC%A7%88%EB%A1%9C%EA%B7%B8-iframe%EC%9C%BC%EB%A1%9C-MFE-%EA%B5%AC%EC%B6%95-%EC%8B%9C-%EC%9D%B8%EC%A6%9D-API-%EB%B0%98%EB%B3%B5%ED%98%B8%EC%B6%9C-%EC%9D%B4%EC%8A%88</guid>
            <pubDate>Tue, 09 Dec 2025 08:41:58 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>남의 삽질로그🪏:</strong>
다른 회사, 다른 사람들의 겪은 문제와 해결방법을 나의 방식으로 정리하는 글입니다.
정리를 통해 인사이트를 얻고, 문제해결력을 기르고자 합니다.</p>
</blockquote>
<ul>
<li>오늘의 글 : <a href="https://oliveyoung.tech/2025-12-08/iframe-postmessage-authentication/">https://oliveyoung.tech/2025-12-08/iframe-postmessage-authentication/</a></li>
</ul>
<h1 id="배경">배경</h1>
<p>iframe으로 MFE 구축함.</p>
<p>MFE 자체에는 인증 시스템이 없었음. </p>
<p>따라서 MFE 내에서 인증 필요 시, 호스트앱으로부터 인증요청하고 토큰을 전달받는 구조.</p>
<p>(postMessage를 사용하여 구현)</p>
<br/>

<h1 id="문제">문제</h1>
<p>이때, MFE에서 동시다발적으로 API를 호출할 경우, API를 호출한 횟수만큼 인증 요청을 보냈음.</p>
<p>최초로 전달받은 토큰 하나만 있어도 충분할텐데, 불필요하게 여러번 요청을 보내고, 여러개의 토큰을 받게 됨. </p>
<br/>

<h1 id="해결">해결</h1>
<p>첫번째 요청 처리 중이라면, </p>
<p>그 다음부터 오는 요청들을 모두 <strong>큐</strong>에 집어넣기. </p>
<p>첫번째 요청에서 응답이 왔다면, 큐에 들어있던 모든 요청들에 대해 같은 응답 보내주는 방식으로 해결.</p>
<h3 id="제약-조건-역추론">제약 조건 역추론</h3>
<ul>
<li>각 요청들은 각각의 서로 다른 API 와 물려있음 - 모든 요청에 대한 응답이 있어야 함. (첫번째만 처리하고 나머지 요청은 무시하면 안됨.)</li>
</ul>
<br/>

<h1 id="어떻게-큐를-떠올렸을까">어떻게 큐를 떠올렸을까?</h1>
<p>여러 요청을 모두 보관해야함. 이때, 요청들이 순차적으로 쌓이고, 첫번째 요청에 대한 응답이 반환되었을 때 처리됨. 즉, 대기열 개념 ⇒ Queue</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[선언적 프로그래밍과 절차적 프로그래밍]]></title>
            <link>https://velog.io/@c-jeongyyun/%EC%84%A0%EC%96%B8%EC%A0%81-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EA%B3%BC-%EC%A0%88%EC%B0%A8%EC%A0%81-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@c-jeongyyun/%EC%84%A0%EC%96%B8%EC%A0%81-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EA%B3%BC-%EC%A0%88%EC%B0%A8%EC%A0%81-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Fri, 31 Oct 2025 02:04:12 GMT</pubDate>
            <description><![CDATA[<p>링크드인을 둘러보다, 문동욱 개발자님이 <a href="https://evan-moon.github.io/2025/09/07/declarative-programming-misconceptions-and-essence/">선언적 프로그래밍에 대해 자세하게 설명해주신 글</a>을 발견했다.</p>
<p>글을 읽고 선언적 프로그래밍 개념에 대한 이해를 넘어, 코드를 작성할 때 중요한 태도가 다시 리마인드되는 부분이 있었다. 그 내용을 기록으로 남기고자 정리를 해본다.</p>
<hr>
<h2 id="절차적-코드">절차적 코드</h2>
<blockquote>
<p>“무엇을 어떻게 할지(How)”를 시간 순서대로 서술하는 코드</p>
</blockquote>
<p>절차적 코드는 목표를 달성하기 위한 단계적인 행위를 기술한다.</p>
<p>아래 예시는 DOM API를 이용해 사용자 프로필을 생성하는 절차적 코드이다.</p>
<pre><code class="language-jsx">function createUserProfile(user) {
  const container = document.createElement(&#39;div&#39;);
  container.className = &#39;user-profile&#39;;

  const nameElement = document.createElement(&#39;h2&#39;);
  nameElement.textContent = user.name;
  container.appendChild(nameElement);

  const emailElement = document.createElement(&#39;p&#39;);
  emailElement.textContent = user.email;
  container.appendChild(emailElement);

  if (user.avatar) {
    const avatarElement = document.createElement(&#39;img&#39;);
    avatarElement.src = user.avatar;
    avatarElement.alt = `${user.name}의 아바타`;
    container.appendChild(avatarElement);
  }

  return container;
}</code></pre>
<p><em>출처: <a href="https://evan-moon.github.io/2025/09/07/declarative-programming-misconceptions-and-essence/">https://evan-moon.github.io/2025/09/07/declarative-programming-misconceptions-and-essence/</a></em></p>
<br/>


<p>사용자 프로필(<code>userProfile</code>)을 만들기 위해 어떤 DOM 요소를 생성하고,</p>
<p>어떤 순서로 속성을 설정하고, 어디에 추가할지 등을 명시적으로 기술하고 있다.</p>
<p>즉, “행위의 순서”가 코드의 핵심이다.</p>
<hr>
<h2 id="선언적-코드">선언적 코드</h2>
<blockquote>
<p>“무엇을 할지(What)”를 중심으로 관계를 표현하는 코드</p>
</blockquote>
<p>선언적 코드는 구현의 절차보다<strong>,  관계나 구조의 표현</strong>에 집중한다.</p>
<p>아래는 같은 기능을 React로 작성한 선언적 코드이다.</p>
<pre><code class="language-jsx">function UserProfile({ user }) {
  return (
    &lt;div className=&quot;user-profile&quot;&gt;
      &lt;h2&gt;{user.name}&lt;/h2&gt;
      &lt;p&gt;{user.email}&lt;/p&gt;
      {user.avatar &amp;&amp; (
        &lt;img src={user.avatar} alt={`${user.name}의 아바타`} /&gt;
      )}
    &lt;/div&gt;
  );
}</code></pre>
<p><em>출처: <a href="https://evan-moon.github.io/2025/09/07/declarative-programming-misconceptions-and-essence/">https://evan-moon.github.io/2025/09/07/declarative-programming-misconceptions-and-essence/</a></em></p>
<br/>

<p>여기서는 “어떤 순서로 렌더링해야 하는가”보다,</p>
<p>UserProfile을 구성하는 요소 간의 관계가 중점적으로 표현된다.</p>
<p>즉, 시간적 순서보다는 <strong>의도와 구조</strong>가 드러난다.</p>
<hr>
<h2 id="절차적-vs-선언적을-구분하는-것-자체는-중요하지-않다">절차적 vs 선언적을 구분하는 것 자체는 중요하지 않다.</h2>
<p>핵심은 “A는 절차적이고, B는 선언적이야”를 구분하는 게 아니라, </p>
<p><strong>현재 다루고 있는 문제의 본질이 무엇인지</strong>를 판단하는 것이라고 생각한다.</p>
<ul>
<li><p><strong>관계 표현</strong>이 중요한 부분이라면 선언적으로 접근하는 게 좋다.</p>
<p>  도메인의 구조를 명확하게 드러낼 수 있기 때문이다.</p>
</li>
<li><p><strong>행위의 순서</strong>나 <strong>구현 효율</strong>이 중요한 부분이라면 절차적으로 작성해도 된다.</p>
<p>  예를 들어 인프라 레벨에서는 안전하고 효율적인 실행이 더 중요하다.</p>
</li>
</ul>
<blockquote>
<p>“비즈니스 로직 레벨에서는 선언적으로 접근하는 것이 좋다.</p>
<p>도메인의 본질적 관계를 표현하는 데 집중해야 하기 때문이다.</p>
<p>반면 인프라 레벨에서는 절차적이어도 괜찮다.</p>
<p>효율적이고 안전한 구현이 더 중요하기 때문이다.</p>
<p>핵심은 경계를 명확히 하고 추상화의 레벨을 맞춰주는 것이다.</p>
<p>어느 레벨에서 어떤 관심사를 다루는지 분명히 구분해야 한다.”</p>
<p>— <a href="https://evan-moon.github.io/2025/09/07/declarative-programming-misconceptions-and-essence/">Evan Moon, <em>선언적 프로그래밍에 대한 착각과 오해</em></a></p>
</blockquote>
<p>결국 선언적 프로그래밍은 <strong>더 이해하기 쉬운 코드</strong>를 작성하기위한 접근 방식이라고 생각한다.</p>
<p>내가 표현하려는 의도를 명확히 파악하고,</p>
<p>그 의도를 가장 잘 드러낼 수 있는 방식을 선택할 수 있느냐가 결국 가장 중요하지 않을까.</p>
<hr>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://evan-moon.github.io/2025/09/07/declarative-programming-misconceptions-and-essence/">선언적 프로그래밍에 대한 착각과 오해 — Evan Moon Blog</a></li>
</ul>
<p>좋은 글을 작성해주신 문동욱 개발자님께 감사의 마음을 전합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[내가 두려워하는 리스크는 진짜 리스크 였을까?]]></title>
            <link>https://velog.io/@c-jeongyyun/%EB%82%B4%EA%B0%80-%EB%91%90%EB%A0%A4%EC%9B%8C%ED%95%98%EB%8A%94-%EB%A6%AC%EC%8A%A4%ED%81%AC%EB%8A%94-%EC%A7%84%EC%A7%9C-%EB%A6%AC%EC%8A%A4%ED%81%AC-%EC%98%80%EC%9D%84%EA%B9%8C</link>
            <guid>https://velog.io/@c-jeongyyun/%EB%82%B4%EA%B0%80-%EB%91%90%EB%A0%A4%EC%9B%8C%ED%95%98%EB%8A%94-%EB%A6%AC%EC%8A%A4%ED%81%AC%EB%8A%94-%EC%A7%84%EC%A7%9C-%EB%A6%AC%EC%8A%A4%ED%81%AC-%EC%98%80%EC%9D%84%EA%B9%8C</guid>
            <pubDate>Fri, 01 Nov 2024 18:09:13 GMT</pubDate>
            <description><![CDATA[<p>오늘 R&amp;D팀 AA님과 커피챗을 했다. </p>
<p>그동안 큰 접점이 없어서 AA님이라는 사람에 대해 잘 몰랐는데, 이번 대화를 통해서 큰 인사이트를 얻을 수 있었다. </p>
<p>내가 AA님께 가장 궁금했던 것은 왜 우리 회사에 합류하게 되었는지였다.</p>
<p>전공이 이 분야도 아니셨고, 이 분야에 대한 관심도가 크진 않으셨던 것으로 알고 있었기 때문이다. </p>
<p>내가 “어떤 이유로 합류를 결정하게 되셨어요?” 라고 여쭸을 때, 
“해보면 좋겠다, 재밌겠다, 라는 생각이 들어서요”라는 답변을 들을 수 있었다. 
제안 받으셨을 때 어떤 직무를 맡는지도 모르셨다고 했다.</p>
<p>나는 어떤 것을 실행할 때, 실패에 대한 리스크를 크게 느끼는 사람이고, 그 부분이 도전을 저지한다고 생각하여 고치려고 노력하고 있다. 그래서 리스크가 있음에도, 어떤 것이 동기가 되어 그렇게 빠르게 결정을 내리셨는지가 궁금했다. 어떤 것이든 잘할 거라는 단단한 자신감이 원동력이 된 것일까? 자신감을 키워야하나? 라는 생각이 들던 찰나에,  돌아오는 답변은,</p>
<blockquote>
<p>*“잃을 게 없다고 생각해서요. 가진 것도 없으니”  *</p>
</blockquote>
<p>충격이었다. </p>
<p>듣자 마자 든 생각은 <em>‘그러게. 난 잃을게 뭐가 그렇게 많다고 걱정을 한거지?’</em> 였다. </p>
<p>내가 그렇게 잃을 게 많았나?</p>
<p>뭐를 잃는 거지? 시간? 그치만 그 시간을 가치를 창출하는데 쓰면 아까운게 아닌데? </p>
<blockquote>
<p>*<em>나는 허상의 리스크랑 싸우고 있는 것이었다. *</em></p>
</blockquote>
<p>허상의 리스크에 대한 걱정 때문에, 크고 작은 도전을 미루기는 너무나 아깝다는 생각이 든다. </p>
<p>물론 그 리스크가 허상이 아니라 실제 리스크라면 전략적으로 접근해야한다.
<br/>
핵심은, <strong>“진짜” 리스크가 맞는지를 판단하는 것.</strong> 이라고 생각한다. 
<br/></p>
<p>무언가를 실행할 떄 리스크가 있는 듯 하여 망설여진다면, 정말 리스크가 맞는지 문제정의를 명확히 해야겠다는 생각이 들었다. 경험상, 어려워 보이는 태스크도 들여다보면 그렇게 어렵지 않은 경우도 많았다. 나는 어려워보이는 태스크를 접근할 때는 divide and conquer 방식처럼, 더이상 어렵지 않아 보일 때까지 태스크를 쪼개본다. 비단 태스크가 아니라, 다양한 도전 과제에 망설임을 느꼈을 때에도, 망설임의 사고 흐름을 쪼개서 글로 써보면 객관화하는데에 도움이 되지 않을까. 잊지 말고 실천해봐야지. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[목표달성률 90%에서 100%로 만들기]]></title>
            <link>https://velog.io/@c-jeongyyun/%EB%AA%A9%ED%91%9C%EB%8B%AC%EC%84%B1%EB%A5%A0-90%EC%97%90%EC%84%9C-%EC%9E%90%EA%BE%B8-%EB%A9%88%EC%B6%94%EB%8A%94-%EB%82%98.-100%EB%A1%9C-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@c-jeongyyun/%EB%AA%A9%ED%91%9C%EB%8B%AC%EC%84%B1%EB%A5%A0-90%EC%97%90%EC%84%9C-%EC%9E%90%EA%BE%B8-%EB%A9%88%EC%B6%94%EB%8A%94-%EB%82%98.-100%EB%A1%9C-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Mon, 14 Oct 2024 02:38:13 GMT</pubDate>
            <description><![CDATA[<h2 id="이전의-해결책-회고하기"><a href="https://velog.io/@c-jeongyyun/%EC%A3%BC%EA%B0%84-%EB%AA%A9%ED%91%9C-%EB%8B%AC%EC%84%B1%EC%97%90-%EB%8C%80%ED%95%B4-%EB%8F%8C%EC%95%84%EB%B3%B4%EA%B8%B0">이전의 해결책</a> 회고하기</h2>
<p>주간 목표를 잘 세우고, 달성해보기로 한지 3주쯤 지났다.
<img src="https://velog.velcdn.com/images/c-jeongyyun/post/bc26ceeb-f2c6-4128-927a-a5b150e8a12c/image.png" alt="노션 기록 내용 _ 화요일은 공휴일"></p>
<p>지난 3주간 주중의 가용시간을 적고, 매일의 태스크를 타당하게 설정한 뒤, 잘하려는 마음보다는 내가 실제로 할 수 있는 양을 기준으로 목표를 세워보았다.</p>
<p>이전에 내가 설정한 솔루션에서는 ‘태스크 소요시간을 너무 적게 잡는 경향이 있으니 1.3배 늘려서 작성하자’ 라고 했는데, 굳이 그럴 필요는 없었다. 저번 글을 작성하면서, 내가 태스크를 수행할 수 있는 속도보다 무리하게 짧은 시간을 공기로 잡은 것이 메타인지가 되었나본지 점점 오차가 줄어들었다. </p>
<p>매일의 가용시간을 적는 것은 아직 완전히 익숙해지지는 않았지만, 내가 하루에 수행할 수 있는 양을 가늠하는데에 역시 도움이 되었다. 저번주에는 회사가  대한민국 ESG 친환경대전에 참여하게 되어 코엑스에 다녀왔는데, 이로 인해 줄어든 가용시간을 잘 고려해서, 무리하지 않게 태스크를 분배할 수 있었다. </p>
<p>이렇게 목표를 잘 설정해보니, 그동안 무리하게 많은 양을 수행하는 것을 목표로 잡음으로써 발생하였던 신체적인 무리와 정신적인 스트레스가 줄어들었다는 게 느껴졌다. 단순히 몸과 마음이 나아진 것뿐만 아니라, 고민하고 생각할 수 있는 힘이 생겨 더 효율적으로 몰입하여 일할 수 있었다. </p>
<br/>


<h2 id="새로운-문제-왜-항상-90정도만">새로운 문제, 왜 항상 90%정도만?</h2>
<p>그래서 결국 목표를 달성했느냐? </p>
<p>아쉽게도 그러진 못했다. 새로운 문제점이 발견되었다. 세운 계획대로 착착착 진행을 잘 하다가, 묘하게 목표에서 한 90% 정도 달성하고 멈춰버리는 일이 자꾸 발생하였다. 그렇다고 목표를 120%로 세워버리면 또 이전처럼 몸과 마음을 혹사하는 것이라…어떻게 해야할지 고민이 되었다.  </p>
<p>나만 이런가 싶은 마음으로 검색을 해보았더니 접근-회피 갈등이라는게 나왔다. 똑같은 지점에서 즐거운 자극과 불쾌한 자극이 동시에 일어나는 경우에 발생하는 갈등이라고 한다.</p>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/55714f5d-729a-485e-8fa5-35a25e2cb33d/image.png" alt="배고픈 쥐를 테이블 위에 둔다. 테이블에 먹이를 두되, 먹이를 먹으러 가는 길에 전기충격을 받도록 하는 실험 환경. 출처:https://espgarde.com/33"></p>
<p>내 심리적 상황이 자연스럽에 이 이론에 대입이 되었다.</p>
<p>내가 목표로 향해가는 길은 바람직한 방향으로 가는 것(접근)이지만, 목표에 가까워질 수록 만약 목표를 달성하지 못하면 어쩌지? 라는 생각(회피)이 들어 자꾸만 목표달성을 회피하는 것 같았다.</p>
<br/>

<h2 id="90를-100로-만들기-위한-솔루션">90%를 100%로 만들기 위한 솔루션</h2>
<p>어떻게 이 회피를 타파해보면 좋을까. </p>
<p>접근-회피 갈등에서 자극에 접근하는 방법은 두가지가 있다.</p>
<ol>
<li>자극에 대한 욕구를 높이기 </li>
<li>회피에 대한 두려움을 줄이기</li>
</ol>
<p>사실 목표를 달성못한다고해서 죽는 건 아니기 때문에(…), 난 2번 방향으로 해결책들을 생각해보았다. </p>
<blockquote>
<p><strong>나의 해결책</strong></p>
<ol>
<li>회피 강도가 높아질 수록 목표에 가까워진 것이라는 걸 리마인드하자. </li>
<li>목표에 가까워진 것은 목표를 달성한게 아니라는 걸 리마인드하자.</li>
<li>목표에 가까워질수록 일을 세밀하게 나눠보자. 그리고 세밀하게 나눈 태스크를 하나씩 끝낸다는 마인드로 접근하자. (목표 달성이라는 거시적인 시야보다는 작은 태스크 하나하나를 끝내는 것에 집중하는 미시적인 태도로 전환해보자)</li>
</ol>
</blockquote>
<p>1, 2는 간단하게 말하자면 스스로 최면을 거는 방법이라고 생각한다. 그동안의 나에 대한 빅데이터를 생각해보았을 때… 자기 최면은 잘 안걸리는 것 같긴하다. 그래서 3번까지 생각해보았다. </p>
<p>나는 미시적인 시야를 가지고 디테일한 것을 조정하는 걸 잘한다. 그래서, 내 시야를 좁게 만들어보고 목표보다는 태스크만 보게 하면 부담감이 덜어지고 회피하고자 하는 마음이 줄어들지 않을까?라는 가설을 세워보았다. 이번 주 부터는 이 가설을 잘 검증해보려고 한다. (해결책 1, 2도 생각날때마다 적용할 예정!) 과연 어떤 결과가 나올지..! 궁금하다. </p>
<br/>

<h2 id="마무리">마무리</h2>
<p>누군가는 이러한 것들을 스스로 너무나 잘 컨트롤하기 때문에, 왜 이렇게까지 할까 라는 생각이 들 수 도 있겠다. 그치만 나는 나의 부족함을 너무나도 인정하기 때문에, 재능이 없으면 노력으로 메꿔야한다는 생각으로 나를 잘 빚어보고자 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[주간 목표 달성에 대해 돌아보기]]></title>
            <link>https://velog.io/@c-jeongyyun/%EC%A3%BC%EA%B0%84-%EB%AA%A9%ED%91%9C-%EB%8B%AC%EC%84%B1%EC%97%90-%EB%8C%80%ED%95%B4-%EB%8F%8C%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@c-jeongyyun/%EC%A3%BC%EA%B0%84-%EB%AA%A9%ED%91%9C-%EB%8B%AC%EC%84%B1%EC%97%90-%EB%8C%80%ED%95%B4-%EB%8F%8C%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Sun, 29 Sep 2024 12:04:19 GMT</pubDate>
            <description><![CDATA[<h2 id="글을-쓰게-된-배경">글을 쓰게 된 배경</h2>
<p>나는 일할 때, 개인의 주간 목표를 설정한다.
요즈음 주간 목표를 달성하지 못해 주말, 심지어는 연휴까지 일을 하는 일이 반복되었는데, 이번주 오랜만에 주간 목표를 완전히 달성하였다.</p>
<p>이번 주 해야할 일을 모두 다 하고 나니, 주말동안 일에 대한 부채감 없이, 알차고 행복한 시간들을 보낼 수 있었다. 토요일에는 친구들과 만나고 기획 책을 읽고, 일요일에는 학교 수업을 듣고, 개인 스터디를 하고 이렇게 여유롭게 회고를 작성하였다. 내가 이상적으로 생각하던, 휴식과 발전이 있는 삶이었다. </p>
<p>장기적으로 보았을 때, 이러한 시간을 보내는 것이 지속가능하게 일할 수 있는 능력을 만들어준다고 생각한다. 5일 동안의 지침을 보상할 수 있는 재충전의 시간과, 개인 스터디를 통한 개발자로서의 능력 향상의 시간. </p>
<p>그래서, 나의 지속가능성을 높여주는 &#39;주간 목표 달성&#39;을 왜 못하고 있었고, 어떻게 더 잘 수행할 수 있을지에 대해 생각하고 정리해보는 시간을 가졌다.</p>
<hr>
<h2 id="🥲-주간-목표-달성이-왜-어려웠을까">🥲 주간 목표 달성이 왜 어려웠을까?</h2>
<p>주간 목표를 달성하지 못한 주에는, 주말까지 업무에 대한 부채감에 스트레스를 받았고, 능력이 충분하지 못한 자기자신에 대해 자괴감이 들었다.</p>
<p>나는 왜 주간 목표를 달성하는게 어려웠을까?</p>
<h3 id="1-ability-판단-미스">1. Ability 판단 미스</h3>
<p>내가 할 수 있을 거라고 생각한 것보다 실제로 내가 할 수 있는 일의 양이 적었다. </p>
<blockquote>
<p><strong>왜 판단 미스가 있었는가?</strong></p>
</blockquote>
<p><strong>a. 변수를 고려하지 않았다.</strong> 
프로그래밍을 하다보면 변수가 항상 발생한다. 그러나 나는 변수들에 대한 패딩을 전혀 고려하지 않고, 이 일을 변수없이 가장 빨리 끝낼 수 있는 시간을 기준으로 일정을 산정하였기 때문에 예상한 만큼 일을 달성하지 못했다. 
솔직히 말하자면, <em>&#39;능력있는 사람으로 인정받으려면 이 정도 소요시간에 이 태스크를 끝내야지&#39;</em>라는 내 워너비를 예상 소요시간으로 잡았던 것 같다. 그것도 아주 극단적으로.</p>
<p>** b. 실질적인 가용시간을 고려하지 않았다.**
나는 현재 학교와 회사를 병행하고 있고, 수업일정이 매주 변경되는 상황이라 가용시간이 유동적이다. 그러나 학교 강의 시간, 출퇴근 소요시간을 제외한 실제 가용시간을 매주 따져보지 않았고, &#39;이 정도는 할 수 있겠지&#39;라는 생각으로 태스크를 할당하였다. 태스크에 대해 전략적으로 대응하지 못했던 거다.</p>
<h3 id="2-외부-변수로-인해-팀의-목표가-빈번히-변경되었다">2. 외부 변수로 인해 팀의 목표가 빈번히 변경되었다.</h3>
<p>우리 회사는 스타트업이기 때문에, 대기업에 비해 변동성이 크다. 이로 인해 팀의 목표가 변경되는 상황이 반번히 일어난다. </p>
<p>(현재 이런 케이스에 대해서는 주간 목표를 변경하는 방식으로 대응하고는 있었으나, 구체적인 해결책을 재고해보고자 적어두었다.)</p>
<br/>



<h2 id="👉-문제를-해결해보자">👉 문제를 해결해보자!</h2>
<p>주간 목표를 좀더 잘 달성하기 위해, 어려웠던 점을 해결할 수 있는 실질적 방법들을 생각해보았다. </p>
<h3 id="첫번째-예상-소요-시간에-패딩-부여하기">첫번째, 예상 소요 시간에 패딩 부여하기</h3>
<p>내가 처음에 할 수 있다고 생각한 시간(초기 예측시간)의 1.3배를 예상 소요시간으로 설정한다.
추후 실제 소요시간을 평균내어, 1.3배가 적절한 수치인지 확인 후 조정한다.</p>
<p>이를 실천하기 위해, 각 태스크마다의 예상 소요시간과 실제 소요시간 측정하여, 노션에 기록해보고자 한다.</p>
<h3 id="두번째-가용시간을-기록하기">두번째, 가용시간을 기록하기</h3>
<p>전 주 일요일에 요일별 가용시간을 기록한다. 가용시간이 변경될 경우, 수행해야할 태스크의 양을 조절한 뒤, 주간 목표가 적절한지 다시 판단한다.</p>
<p>이를 실천하기 위해, 내가 매주 적는 주간 목표 노션 페이지에 요일별로 가용시간을 적어놓을 거다.</p>
<h3 id="세번째-외부-변수로-인한-팀-목표-변경에-대응하기">세번째, 외부 변수로 인한 팀 목표 변경에 대응하기</h3>
<p>외부 변수로 인한 팀 목표 변경 유형은 아래와 같이 나눌 수 있다.</p>
<blockquote>
<p><strong>1. 새로운 업무가 추가됨.</strong>
<strong>2. 마감일이 앞당겨짐.</strong></p>
</blockquote>
<p>각각에 대한 해결책은 아래와 같다.</p>
<ol>
<li>새로운 업무가 추가되는 경우, 새로운 업무를 주간 목표에 추가하고, 해당 비중만큼 기존 목표를 줄인다.</li>
<li>마감일이 앞당겨졌을 경우, 해당 부서와의 회의를 통해 해당 시간동안 달성할 수 있도록 태스크를 조정한다. 불가능할 경우에만 주말까지 투자한다.</li>
</ol>
<br/>

<h2 id="🚀-높은-퀄리티의-목표를-달성하기-위하여">🚀 &quot;높은 퀄리티의 목표&quot;를 달성하기 위하여</h2>
<p>앞서 주간 목표를 달성하지 못했던 이유를 생각해보고, 그것에 대한 해결책을 만들어 보았다.
그러나 아무리 해결책을 잘 실천해도, 주간 목표의 퀄리티가 떨어진다면, 달성하는 의미가 없다. </p>
<p>예를 들어 주간 목표를 달성하기 위해 태스크를 아주 적게 할당하거나, 팀의 목표와 달리 전혀 쓸데없는 것들을 주간 목표로 설정하였다면? 일주일동안 나와 회사의 발전에 하등 쓸모없는 행위를 한 것이다.</p>
<p>그래서 내가 생각하는 &quot;높은 퀄리티의 목표&quot;가 무엇이고, &quot;퀄리티 높은 목표였는지&quot;에 대해서 평가하는 방법도 생각해보았다. </p>
<h3 id="높은-퀄리티의-목표란">높은 퀄리티의 목표란?</h3>
<p>높은 퀄리티의 목표는 아래 두가지로 생각해보았다.</p>
<blockquote>
<p><strong>1. 나의 총력을 다했을 떄 목표를 달성할 수 있어야 함.</strong>
<strong>2. 팀의 목표를 달성할 수 있어야 함.</strong></p>
</blockquote>
<p>우선 목표를 달성하기 위해 최선을 다할 수 있어야 한다.
왜? 내가 하는 일에 모든 능력을 끌어다쓰는 것이 일에 대한 나의 태도이고, 장기적으로 내가 더 높은 가치를 가진 인력이 될 수 있는 방법이기도 하다.</p>
<p>그리고 나의 목표를 달성하면, 팀의 목표를 달성할 수 있어야 한다. 우리 회사, 팀이 하고자 하는 것을 안한다? 회사와 팀에 소속되어있음에 대한 의무를 안지키는 거다.  <del>그럴거면 회사 왜 다니니.</del></p>
<h3 id="목표의-퀄리티-평가하기">목표의 퀄리티 평가하기</h3>
<p>높은 퀄리티의 목표가 무엇인지 정의하였으니, 내가 설정한 목표의 퀄리티를 평가할 수 있어야 한다. 앞서 말했다시피 단순히 목표 달성 여부로 목표의 퀄리티가 좋았다고 평가할 수 없기 때문. </p>
<p>그래서 세가지 항목으로 평가기준을 매겨 보았다.</p>
<blockquote>
<p><strong>1. 총력을 다했는지? (0<del>10)
2. 내 ability(총력)를 적절히 판단하였는지? (0</del>10)
3. 주간 목표를 달성함으로써 팀의 목표도 달성하였는지? (0~10)</strong></p>
</blockquote>
<p>정량적으로 평가할 수 없는 요소들이라 점수화를 해보았다. 매주 점수를 합산하여 목표의 퀄리티를 판단해보려고 한다. </p>
<br/>


<hr>
<h2 id="마무리하며">마무리하며</h2>
<p>오랜만에 글을 통해 나의 문제점을 되짚어 보고, 더 나아가기 위한 방법에 대해 서술해보았다.
내가 생각하는 나 자신을 돌아보고, 내 가치관도 다시금 확인할 수 있는 시간이었다.</p>
<p>회고를 통해 만들어본 해결책들은 이번주부터 적용해볼 예정이다. 적용뿐만 아니라 현실적으로 실천할 수 있는 방식이 맞는지 판단해보고 그에 맞게 수정하며 점진적으로 발전시키려고 한다.</p>
<p>나의 지속가능성을 위해서!🚀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[품질 높은 소프트웨어를 만들어야 하는 이유(아주 짧은 생각 정리)]]></title>
            <link>https://velog.io/@c-jeongyyun/%ED%92%88%EC%A7%88-%EB%86%92%EC%9D%80-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%96%B4%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%95%84%EC%A3%BC-%EC%A7%A7%EC%9D%80-%EC%83%9D%EA%B0%81-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@c-jeongyyun/%ED%92%88%EC%A7%88-%EB%86%92%EC%9D%80-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%96%B4%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%95%84%EC%A3%BC-%EC%A7%A7%EC%9D%80-%EC%83%9D%EA%B0%81-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 04 Apr 2024 17:55:06 GMT</pubDate>
            <description><![CDATA[<p>소프트웨어는 결국 어떤 기능을 실현하기 위한 수단이다. 소기의 목적을 달성하기 위해서, 실제 내부에서는 어떤 기술로 구현을 하는지는 크게 관계가 없다. </p>
<p>그치만 우리가 기술을 신경쓰는 이유는 무엇일까?</p>
<p>사람이 가지고 있는 자원과 시간은 한정적이기 때문이다. </p>
<p>따라서 최대한 효율적으로 소기의 목적을 달성하고자 하며, 그를 위해 현재 상황에 가장 적합한 기술을 선택해야한다.</p>
<p>그렇다고 하여 무조건 빨리 구현하는 것이 좋은 방법은 아니다. 대부분의 소프트웨어는 일회용으로 사용되기보다는, 점진적으로 새로운 기능들을 추가하고, 기존의 기능들을 변경하며 더 많은 가치를 제공하려 한다. </p>
<p>따라서 우리와 같은 기술자들은, 앞으로 펼쳐질 미래까지 고려하여 소프트웨어가 더 많은 가치를 제공할 수 있도록 해야한다. 그렇기 때문에 소프트웨어의 유지보수성, 확장성, 가독성을 고려하며 기능을 구체화해야하는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[바이너리 코드, 바이트 코드, 기계어]]></title>
            <link>https://velog.io/@c-jeongyyun/%EB%B0%94%EC%9D%B4%EB%84%88%EB%A6%AC-%EC%BD%94%EB%93%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EA%B8%B0%EA%B3%84%EC%96%B4</link>
            <guid>https://velog.io/@c-jeongyyun/%EB%B0%94%EC%9D%B4%EB%84%88%EB%A6%AC-%EC%BD%94%EB%93%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EA%B8%B0%EA%B3%84%EC%96%B4</guid>
            <pubDate>Sat, 03 Feb 2024 10:56:09 GMT</pubDate>
            <description><![CDATA[<h1 id="계기">계기</h1>
<p>V8이 자바스크립트를 바이트 코드(bytecode)로 컴파일하고 실행한다는 내용을 보고, 바이트 코드에 대한 내용을 찾아보게 되었다. 처음에는 바이트 코드와 바이너리 코드가 동치인줄 알았어서 바이너리 코드에 대한 내용을 정리해보았고, 바이트 코드의 개념에 대해 읽다가 바이트 코드와 기계어는 어떻게 다른지가 궁금해져 관련 내용들을 찾아 정리하게 되었다. </p>
<br/>

<h1 id="정리">정리</h1>
<h2 id="바이너리-코드binary-code">바이너리 코드(Binary code)</h2>
<p>2심볼 시스템을 사용하는 데이터를 의미한다. 주로 이진수 체계의 0과 1을 의미한다 (0, 1이 각각 데이터 하나를 나타냄). 한국어로는 이진 코드라 불린다. </p>
<h2 id="기계어machine-language">기계어(Machine language)</h2>
<p><strong>CPU</strong>가 해독하고 실행할 수 있는, 비트 단위(0, 1)로 이루어진 <strong>컴퓨터 언어</strong>를 통틀어 말한다. 어셈블리어와 1:1로 대응한다. </p>
<h2 id="바이트-코드byte-code">바이트 코드(Byte code)</h2>
<p>CPU와 같은 특정 하드웨어가 아닌, <strong>가상 컴퓨터</strong>에서 작동하는 실행 프로그램을 위한 <strong>이진</strong> <strong>표현법</strong>이다. 가상컴퓨터 위에서 작동하기 때문에, 특정 하드웨어에 종속되지 않는다는 특징을 가지고 있다. 즉, 하드웨어에 대한 의존성이 낮다고 말할 수 있다. </p>
<p>바이트 코드는 컴파일 과정을 거쳐서 생성된다. 생성된 바이트 코드는, 주로, 한번에 한 명령어만 읽어 실행하는 인터프리팅 방식으로 실행이 된다. </p>
<h2 id="바이너리-코드-기계어-바이트-코드간의-관계">바이너리 코드, 기계어, 바이트 코드간의 관계</h2>
<p>기계어와 바이트 코드는 모두 0과 1로 이루어져있으므로, 바이너리 코드로 이루어졌다고 말할 수 있다. </p>
<p>기계어는 하드웨어가 이해할 수 있는 컴퓨터 언어이고, 바이트 코드는 하드웨어가 아닌 가상 컴퓨터에서 실행시킬 수 있는 코드이다. 기계어로 쓰여진 코드이냐, 바이트 코드이냐에 따라 실행할 수 있는 환경이 다르다는 것이 차이점이라고 할 수 있다. </p>
<br/>

<h1 id="느낀-점">느낀 점</h1>
<p>각 용어들에 대한 개념들을 정리해본 시간이었다. 머릿속으로는 알고 있었던 개념들도 있었지만, 막상 글로 풀어내려니 명확히 알고 있지 않은 부분들이 보였다. </p>
<p>요즘 글쓰기의 중요성을 계속 느낀다. 시간이 좀 더 걸리더라도, 당장 다음 내용으로 넘어가고 싶은 급한 마음이 들더라도, 글로 차곡 차곡 정리해보려고 한다. 나만의 지식 자산을 많이 만들겠어🥹</p>
<hr>
<blockquote>
<h3 id="참고">참고</h3>
<ul>
<li><a href="https://ko.wikipedia.org/wiki/%EC%9D%B4%EC%A7%84_%EC%BD%94%EB%93%9C">이진 코드</a></li>
<li><a href="https://ko.wikipedia.org/wiki/%EA%B8%B0%EA%B3%84%EC%96%B4">기계어</a></li>
<li><a href="https://ko.wikipedia.org/wiki/%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C">바이트코드</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[yarn PnP 사용 시 vscode에 typescript 세팅하기⚙️
]]></title>
            <link>https://velog.io/@c-jeongyyun/yarn-PnP-%EC%82%AC%EC%9A%A9-%EC%8B%9C-vscode%EC%97%90-typescript-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@c-jeongyyun/yarn-PnP-%EC%82%AC%EC%9A%A9-%EC%8B%9C-vscode%EC%97%90-typescript-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 20 May 2023 08:33:58 GMT</pubDate>
            <description><![CDATA[<h2 id="🏞️-글-작성-배경">🏞️ 글 작성 배경</h2>
<p>yarn PnP모드로 전환 후 vscode의 typescript가 제대로 적용되지 않아 애를 먹었었다. 그래서 블로그글을 막 구글링하여 일단 세팅을 했었는데, 내가 어떤 명령어를 수행하고 뭐가 일어났는지 전혀 모르겠더라.   </p>
<p>그래서 공식 문서를 기반으로 몰랐던 부분을 다시 짚어가며 정리를 해보았다! </p>
<h2 id="✨-과정">✨ 과정</h2>
<p>yarn PnP모드 사용 시, vscode와 같은 smart IDE에서는 TypeScript를 위한 특별한 설정이 필요하다.</p>
<h3 id="editor-sdks-생성-및-세팅하기">editor SDKs 생성 및 세팅하기</h3>
<pre><code>yarn dlx @yarnpkg/sdks</code></pre><p>위 명령어를 실행하면 editor SDKs가 생성되고 설정들이 세팅된다.</p>
<blockquote>
<p><code>yarn dlx 패키지</code> : 임시 환경에서 패키지를 실행할 때 사용하는 명령어</p>
<ul>
<li>참고: <a href="https://yarnpkg.com/cli/dlx">https://yarnpkg.com/cli/dlx</a></li>
</ul>
</blockquote>
<ul>
<li><p><code>@yarnpkg/sdks</code> 패키지를 이미 가지고 있는 경우라면 <code>yarn sdks</code>명령어를 통해 editor SDKs 생성 및 설정 세팅을할 수 있다. 아래 명령어 중 적합한 놈을 실행해주면 된다.</p>
<ul>
<li><p><code>yarn sdks vscode vim</code>: yarn에서 지원하는 editors(vscode, vim)에 맞는 base SDKs를 생성하고 설정 세팅해준다.</p>
</li>
<li><p><code>yarn sdks base</code>: yarn에서 지원하지 않는 editors를 위한 명령어로, base SDKs만 설치해주고 세부 설정들은 직접 세팅해주어야 한다.</p>
</li>
<li><p><code>yarn sdks</code> : 모든 설치된 SDKs와 editor settings를 업데이트 할 때 사용한다.</p>
</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>참고❗️</strong><br>yarn PnP 모드에서는 패키지를 zip형태로 관리한다. 따라서 사용한 패키지의 원래 코드를 보기위해서는 (go-to-definitions 기능을 사용하기 위해서는) <a href="https://marketplace.visualstudio.com/items?itemName=arcanis.vscode-zipfs">ZipFS</a>와 같이 zip 저장소에 저장된 파일들을 바로 읽을 수 있는 extension을 설치해주어야 한다.</p>
</blockquote>
<br/>

<h3 id="vscode에서-ts-설정-명시적으로-활성화하기">vscode에서 TS 설정 명시적으로 활성화하기</h3>
<p>vscode를 사용하는 경우, 보안문제로 인해 타입스크립트 설정을 명시적으로 수행해주어야 한다.</p>
<ol>
<li><code>yarn dlx @yarnpkg/sdks vscode</code> 실행 - 위의 <a href="">editor SDKs 생성 및 세팅하기</a>에서 이미 실행해주었다면 다시 할 필요 없음.</li>
<li><code>cmd</code> + <code>shift</code> + <code>p</code> =&gt; <code>Setting TypeScript Version</code> 입력 =&gt; 엔터</li>
<li><code>Use Workspace Version</code> 클릭</li>
</ol>
<br/>





<h2 id="📖-참고">📖 참고</h2>
<ul>
<li><a href="https://yarnpkg.com/getting-started/editor-sdks">https://yarnpkg.com/getting-started/editor-sdks</a></li>
<li><a href="https://yarnpkg.com/getting-started/editor-sdks#editor-setup">https://yarnpkg.com/getting-started/editor-sdks#editor-setup</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[VS Code 커스텀 snippet 만들기✨]]></title>
            <link>https://velog.io/@c-jeongyyun/VS-Code-%EC%BB%A4%EC%8A%A4%ED%85%80-snippet-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@c-jeongyyun/VS-Code-%EC%BB%A4%EC%8A%A4%ED%85%80-snippet-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Sun, 14 May 2023 04:23:59 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-배경">💡 배경</h2>
<p>우리 조직에서 자주 사용하는 코드들이 있다. 
<code>consolelog(&quot;변수명&quot;,변수)</code>라던지, <em>(<code>console.log</code> 아님)</em>
<code>const dispatch = useAppDispatch()</code> 라던지, 
<code>const {변수명} = useAppSelector(state =&gt; state.슬라이스명)</code>이라던지...</p>
<p>위와 같은 코드들을 정말 많이 사용하고 있으나, 항상 이것들을 직접 타이핑했었다. 짧지 않은 코드들을 반복해서 입력하는 것이 귀찮기도 했거니와, 반복되는 코드들을 간단하게 입력할 수 있는 방법이 있다면 코드 타이핑에 소요되는 시간이 많이 단축될 것이라고 생각했다. 
짧은 시간내에 많은 결과물을 만들어야하는 우리 조직에서, 시간 단축은 아주 금 같은 것...! </p>
<p>따라서 이를 해결하기 위해, 짧은 예약어로 특정 패턴의 코드를 간단히 생산할 수 있는 <strong>코드 snippet</strong>을 해결책으로 떠올렸다. </p>
<p>그럼 우리 조직의 생산성을 위해, 우리 조직에 맞는 커스텀 snippet을 만들어보자! </p>
<h2 id="⚒️-스니펫-만들기">⚒️ 스니펫 만들기</h2>
<h3 id="1-커스텀-스니펫-파일-만들기">1. 커스텀 스니펫 파일 만들기.</h3>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/3b6f34fb-f13c-4d4e-ae28-8c6b7d30150e/image.png" alt="">맥북 기준 <code>cmd</code> + <code>shift</code> + <code>p</code> (윈도우 <code>ctrl</code> + <code>shift</code> + <code>p</code>) 입력하여 &quot;Configure user Snippet&quot; 검색 후 클릭! </p>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/af9e92db-1cbe-40bf-93ee-34abc963c2af/image.png" alt="">클릭을 하면 위와 같은 화면이 나타난다. 
프로젝트와 관계없이 전역적으로 해당 스니펫을 적용하고 싶다면, <code>New Global Snippets file...</code>을, 해당 프로젝트에만 적용하고 싶다면 <code>New Snippets for &#39;프로젝트명&#39;...</code> 이라는 명령어를 클릭하면 된다. </p>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/90b91352-dd1b-4591-ae3a-07264bdab230/image.png" alt="">
빈칸에는 원하는 snippet 이름을 붙여주면 된다. 나는 sample이라고 이름을 붙여주었다. 입력하고 엔터를 눌러주면 아래와 같이 <code>snippet이름.code-snippets</code>라는 이름을 가진 파일이 생성된다. </p>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/fbca6f47-2870-4daa-a404-8a89a19d1638/image.png" alt=""></p>
<br/>

<h3 id="2-스니펫-문법에-맞게-스니펫-작성하기">2. 스니펫 문법에 맞게 스니펫 작성하기</h3>
<p>해당 파일안에 아래와 같이 스니펫을 작성해보았다. (주석은 지워줬음)
<img src="https://velog.velcdn.com/images/c-jeongyyun/post/d4caeab8-a280-4e7a-8383-352f06a6e26d/image.png" alt=""></p>
<p><strong>코드</strong></p>
<pre><code class="language-ts">{
  &quot;Print to console&quot;: {
    &quot;scope&quot;: &quot;javascriptreact,typescriptreact,javascript, typescript&quot;,
    &quot;prefix&quot;: &quot;lg&quot;,
    &quot;body&quot;: [&quot;console.log(&#39;$1&#39;);&quot;, &quot;$2&quot;],
    &quot;description&quot;: &quot;Log output to console&quot;
  },

  &quot;For Loop&quot;: {
    &quot;scope&quot;: &quot;javascriptreact,typescriptreact,javascript, typescript&quot;,
    &quot;prefix&quot;: [&quot;for&quot;, &quot;for-const&quot;],
    &quot;body&quot;: [&quot;for (const ${2:element} of ${1:array}) {&quot;, &quot;\t$0&quot;, &quot;}&quot;],
    &quot;description&quot;: &quot;A for loop.&quot;
  }
}
</code></pre>
<ul>
<li><p><code>제목</code> : 스니펫의 제목을 입력해주면 된다. 스니펫마다 구분이 되도록 작성해주어야 한다.  </p>
</li>
<li><p><code>scope</code> : snippet이 적용될 언어를 작성해주면 된다. 여러개의 언어를 지원하고 싶은 경우 콤마로 구분을 해주면 된다. scope를 아예 작성하지 않을 경우, 모든 언어에 대해 스니펫이 적용된다. 다양한 언어플랫폼을 사용하는 경우 scope별로 작성하는 것이 효율적일 수 있다! 그러나 나는 현재 js, ts만 사용하고 있어 scope를 생략해주었다.  </p>
<blockquote>
<p><strong>주의❗️</strong> 
<code>jsx</code>, <code>tsx</code> 파일에도 스니펫을 적용하고 싶은 경우, scope에 
<code>javascriptreact, typescriptreact</code>를 추가로 적어주어야 한다. <code>&quot;javascript, typescript&quot;</code> 만 적어주면 <code>jsx</code>, <code>tsx</code> 파일에서는 적용이 안된다. </p>
</blockquote>
</li>
<li><p><code>prefix</code>: 스니펫을 실행시킬 단축어. 배열안에 여러개의 단축어를 집어넣을 수 도 있다. </p>
</li>
<li><p><code>body</code>: 스니펫 실행 시 실제로 작성해줄 코드를 의미한다. 자세한 문법은 아래를 참고. </p>
<ul>
<li><strong>Tab Stop</strong>
<code>$1</code> , <code>$2</code> 등으로 스니펫이 실행 후 커서가 위치할 곳을 지정해준다.  <code>$</code> 뒤에 붙은 <code>숫자</code> 순으로 커서가 이동되며, 커서의 이동은 <code>tab 버튼</code> 으로 실행할 수 있다. </li>
</ul>
<hr>
<ul>
<li><strong>Placeholder</strong>
<code>${1:something1}</code>, <code>${2:something2}</code>형식으로 작성해줄 수 있다. Tab Stop과 마찬가지로 커서의 위치를 지정할 수 있고, 커서의 위치에 그 뒤에 적어준 문자가 <code>placeholder</code>로 들어가게 된다. 중첩된 형식으로도 작성할 수 있다. ex.<code>${1:parents ${2:child}}</code></li>
</ul>
<hr>
<ul>
<li><strong>Choice</strong>
커서가 위치하는 곳에 들어갈 수 있는 옵션들을 미리 작성해줄 수 있다. <code>${1|one,two,three|}</code>형태로 작성하였을 경우, 커서위치에서 <code>one</code>,<code>two</code> 또는 <code>three</code> 중에 하나의 값을 선택할 수 있다. </li>
</ul>
<hr>
<ul>
<li><strong>Variables</strong> 
vscode에서 지정해준 변수명을 통해 스니펫이 실행되는 파일 이름이라던지, 코드라인 번호라던지 등을 변수로 삽입할 수 도 있다!<code>$변수명</code> 또는 <code>${name:default}</code> 형태로 사용할 수 있다. 변수명의 종류는 <a href="https://code.visualstudio.com/docs/editor/userdefinedsnippets#_variables">링크</a>를 참고하자.</li>
</ul>
</li>
<li><p><code>description</code> : 스니펫에 대한 세부적인 설명을 적어주면 된다. </p>
</li>
</ul>
<br/>

<h3 id="3-실행-예시">3. 실행 예시</h3>
<p>위의 snippet들 중 <code>For Loop</code> 이라는 제목을 가진 스니펫을 실행해보았다. 
실행결과는 아래와 같다. <img src="https://velog.velcdn.com/images/c-jeongyyun/post/5d036bb6-c389-48ad-8588-c2a9648f582e/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/75d45179-53bc-4afe-aa04-52e11c45d68d/image.png" alt=""></p>
<h2 id="✨-나의-결과물">✨ 나의 결과물</h2>
<pre><code class="language-ts">{
  &quot;Console log&quot;: {
    &quot;prefix&quot;: [&quot;cl&quot;, &quot;clog&quot;],
    &quot;body&quot;: [
     &quot;consolelog$1(&#39;🔊 ~ $TM_FILENAME:$TM_LINE_NUMBER $CLIPBOARD&#39;, $CLIPBOARD);&quot;,
      &quot;$2&quot;
    ],
    &quot;description&quot;: &quot;Log the text in clipboard with consolelog function&quot;
  },

  &quot;Create dispatch object&quot;: {
    &quot;prefix&quot;: &quot;dsp&quot;, // dispatch
    &quot;body&quot;: [&quot;const dispatch = useAppDispatch$1()&quot;, &quot;$2&quot;],
    &quot;description&quot;: &quot;Create dispatch object from useAppDispatch hook&quot;
  },

  &quot;Get redux state&quot;: {
    &quot;prefix&quot;: &quot;uaps&quot;, //useAppSelector
    &quot;body&quot;: [&quot;const {$2} = useAppSelector(state =&gt; state.${1:sliceName})&quot;, &quot;$3&quot;],
    &quot;description&quot;: &quot;Get redux state from useAppSelector hook&quot;
  }
}</code></pre>
<p>짜란-!</p>
<p>간단히 설명을 덧붙여보겠다! </p>
<ul>
<li><p><strong><code>Console log</code></strong></p>
<p>단어를 선택하여 복사한 뒤, 원하는 위치에 해당 스니펫을 사용하면 <code>consolelog(&#39;🔊 ~ 파일명:코드라인 넘버 복사한 단어&#39;, $복사한 단어);</code> 형태로 코드가 작성된다. 커서는 <code>consolelog</code> 바로 뒤에 넣어, 해당 함수가 import 되지 않았을 때 바로 import할 수 있도록 만들어주었다.<img src="https://velog.velcdn.com/images/c-jeongyyun/post/639102cb-b93d-41a8-8529-98e11ab5a838/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/bb857566-02c7-4c88-8baf-92a0e8ab5fbb/image.png" alt=""> </p>
</li>
</ul>
<hr>
<ul>
<li><p><strong><code>Create dispatch object</code></strong> </p>
<p>스니펫을 실행하면 <code>const dispatch = useAppDispatch()</code> 코드가 생성된다. <code>Console log</code>와 마찬가지로 <code>useAppDispatch</code>가 import 되지 않았을 때 바로 import할 수 있도록 커서를 배치해주었다.<img src="https://velog.velcdn.com/images/c-jeongyyun/post/4235668f-4a3f-4abc-8ecd-8d5ea5697d4e/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/d425dade-b9ba-49c8-b829-168ef3373693/image.png" alt=""></p>
</li>
</ul>
<hr>
<ul>
<li><strong><code>Get redux state</code></strong>
스니펫을 실행하면 <code>const {$2} = useAppSelector(state =&gt; state.$1)</code> 코드가 생성된다. 커서 1번 위치에 sliceName을 placeholder로 주어, 무엇을 입력해야하는지 명시해주었다. 또한, sliceName을 먼저 입력하면, 해당 slice의 state들을 가져올 때, 자동완성을 사용할 수 있으므로 커서 위치를 slice - state 순으로 배치하였다. 
<img src="https://velog.velcdn.com/images/c-jeongyyun/post/f5b56057-17ab-4f87-9e94-01b1b8a60702/image.png" alt=""> <img src="https://velog.velcdn.com/images/c-jeongyyun/post/902ac9f7-4e1a-4b9d-8257-a183914c4098/image.png" alt=""></li>
</ul>
<br/>

<h2 id="🤔-느낀-점-및-고민">🤔 느낀 점 및 고민</h2>
<p>해당 스니펫으로 조직의 생산성이 향상될 생각을 하니 굉장히 두근두근하다ㅎㅎ 
얼른 팀원들에게 공유하고 싶다. </p>
<p>그런데 이때 든 생각. </p>
<p>공유는 어떻게 하지?... 파일로 공유하게 되면 스니펫을 업데이트 할 때마다 모두가 이를 갱신해주어야 한다. 이것이 절대 좋은 해결책은 아닐 터. </p>
<p>따라서 이 다음으로는, 제작한 스니펫을 익스텐션으로 배포해보고자 한다. 
나의 작은 도전기, 다들 함께 해요!  </p>
<h2 id="참고">참고</h2>
<ul>
<li><p><a href="https://code.visualstudio.com/docs/editor/userdefinedsnippets">https://code.visualstudio.com/docs/editor/userdefinedsnippets</a></p>
</li>
<li><p><a href="https://www.youtube.com/watch?v=umeqCopb96w">https://www.youtube.com/watch?v=umeqCopb96w</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[git flow로 hotfix 하기🚑]]></title>
            <link>https://velog.io/@c-jeongyyun/git-flow-%EB%A1%9C-hotfix-%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@c-jeongyyun/git-flow-%EB%A1%9C-hotfix-%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 04 Mar 2023 07:03:39 GMT</pubDate>
            <description><![CDATA[<p>그동안 수동으로 hotfix 브랜치를 만들어서 hotfix작업을 진행했는데, 
이번에는 <strong>git flow</strong>를 이용해보았다.<br>git-flow로 hotfix하는 과정은 아래와 같다.</p>
<blockquote>
<p>참고: git flow extension이 설치되어있다는 것을 전제로한 글입니다.  </p>
</blockquote>
<h2 id="✨how-to-do">✨How to do</h2>
<h3 id="0️⃣-git-flow-init-명령어를-실행한다">0️⃣ <strong><code>git flow init</code> 명령어를 실행한다.</strong></h3>
<p><code>git flow init</code>은 Git Flow branching Model에 맞게 git repo를 초기화하기 위한 명령어이다.</p>
<p>이 명령어를 실행하면, Git Flow branching Model의 컨벤션을 따르는 branch가 생성되고, feature, hotfix, release와 같은 브랜치의 prefix(접두어)가 지정된다.</p>
<blockquote>
<p><strong>feature, hotfix, release가 브랜치의 prefix(접두어) 인 이유</strong> &gt; <code>feature/popup</code>, <code>hotfix/1.0.2</code>, <code>release/1.3.0</code> 등의 형태로 사용되기 때문</p>
</blockquote>
<p>또한, 이 명령어를 실행한 뒤에는, 이 git flow extension에서 제공하는 명령어들을 이용하여 쉽게 Git Flow branching Model 대로 브랜치들을 관리할 수 있게 된다.</p>
<p>아, 이미 이 명령어가 실행된 적이 있다면, 굳이 다시 하지 않아도 된다. 말그대로 초기화이니까!</p>
<br/>

<h3 id="1️⃣-git-flow-hotfix-start-버전명-을-실행한다">1️⃣ <strong><code>git flow hotfix start 버전명</code> 을 실행한다.</strong></h3>
<p>이 명령어를 실행하면, <code>hotfix/버전명</code>의 브랜치가 생성된다.</p>
<p>이때 해당 명령어를 실행하는 브랜치명이 꼭 main이 아니어도 된다.
다른 브랜치에서 실행해도, 알아서 main브랜치에서 따와진다.
이러한 실수를 줄일 수 있는 요소가 git flow 사용의 장점이 아닐까 싶다.</p>
<br/>

<h3 id="2️⃣-hotfix할-요소들을-고치고-커밋한다">2️⃣ <strong>hotfix할 요소들을 고치고, 커밋한다.</strong></h3>
<p>여기는 부가설명할게 없다. 고치고 <code>hotfix/버전명</code>브랜치에 커밋!</p>
<br/>

<h3 id="3️⃣-git-flow-hotfix-finish-버전명-명령어를-실행한다">3️⃣ <strong><code>git flow hotfix finish 버전명</code> 명령어를 실행한다</strong></h3>
<p>위의 명령어를 실행하면, <code>hotfix/버전명</code>의 커밋 내용이 <strong>로컬</strong>의 <code>main</code>과 <code>develop</code>에 각각 merge된다.
그리고 <code>hotfix/버전명</code> 브랜치는 로컬에서 삭제되며, &quot;버전명&quot;의 이름을 가진 tag가 생성된다.</p>
<p>그리고 현재 브랜치는 develop 브랜치가 된다.</p>
<br/>

<h3 id="4️⃣-로컬의-main과-develop브랜치를-각각-origin의-main과-develop에-push-해준다">4️⃣ <strong>로컬의 <code>main</code>과 <code>develop</code>브랜치를 각각 origin의 <code>main</code>과 <code>develop</code>에 push 해준다.</strong></h3>
<p>현재 hotfix한 내용들은 local에만 반영이 되어있다. 따라서, 이를 원격 repo에도 반영을 각각 해주어야 한다.</p>
<blockquote>
<ul>
<li>local main -&gt; origin main</li>
<li>local develop -&gt; origin develop</li>
</ul>
</blockquote>
<p>만약 upstream repo를 따로 두어 pr로 관리하는 프로젝트라면, origin에 push한 내용들을 PR로 올려주면 된다.</p>
<blockquote>
<ul>
<li>origin main -&gt; upstream main</li>
<li>origin develop -&gt; upstream develop</li>
</ul>
</blockquote>
<blockquote>
<p><strong>⚠️주의</strong><br>현재 브랜치가 무엇인지 잘 확인하고 push해야 한다.<br><code>git flow hotfix finish 버전명</code> 명령어 실행 후 에는 <code>develop</code> 브랜치가 현재 브랜치로 설정된다.</p>
</blockquote>
<br/>

<h3 id="5️⃣-git-push-remote명---tags-명령어를-통해-원격-repo에-태그를-반영한다">5️⃣ <strong><code>git push remote명 --tags</code> 명령어를 통해 원격 repo에 태그를 반영한다.</strong></h3>
<p>origin에 반영하려면 <code>git push origin --tags</code>를,<br>upstream에 반영하려면 <code>git push upstream --tags</code>를 하면 된다.</p>
<p>위의 명령어는, 원격 repo에는 없고 로컬에만 있는 모든 태그들을 repo에 반영하는 명령어이다.<br>만약 특정한 한개의 태그만 반영하고 싶다면,<br><code>git push remote명 태그명</code> 명령어를 사용하면 된다.</p>
<blockquote>
<p><strong>참고</strong><br>로컬의 태그 확인하는 명령어: <code>git tag</code></p>
</blockquote>
<br/>

<h2 id="🎙️느낀-점">🎙️느낀 점</h2>
<p>git flow extension을 사용함으로써 사람이 수동으로 해야하는 것들을 효과적으로 줄일 수 있다는 것을 체감했다.<br>위의 내용들을 테스트해보면서, git flow가 제공하는 feature 등의 기능도 사용해보았는데, 기능개발이 끝난 뒤 로컬과 origin의 feature 브랜치를 모두 지워줘서 굉장히 편리했다.  </p>
<p>그동안은 겁먹어서(...) 잘 안썼는데, 이제부터라도 열심히 써야겠다. ㅠ<br>새로운 기술은 입문이야 어렵지 시작하면 별거 아니라는 것,<br>그리고 그 기술을 도입함으로써 많은 시간을 단축할 수 있다는 것을 다시 기억하자. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트 구현 시 기준 해상도 설정의 중요성📱]]></title>
            <link>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%A0%ED%8A%B8-%EA%B5%AC%ED%98%84-%EC%8B%9C-%EA%B8%B0%EC%A4%80-%ED%95%B4%EC%83%81%EB%8F%84-%EC%84%A4%EC%A0%95%EC%9D%98-%EC%A4%91%EC%9A%94%EC%84%B1</link>
            <guid>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%A0%ED%8A%B8-%EA%B5%AC%ED%98%84-%EC%8B%9C-%EA%B8%B0%EC%A4%80-%ED%95%B4%EC%83%81%EB%8F%84-%EC%84%A4%EC%A0%95%EC%9D%98-%EC%A4%91%EC%9A%94%EC%84%B1</guid>
            <pubDate>Mon, 13 Feb 2023 09:59:45 GMT</pubDate>
            <description><![CDATA[<p>항상 개발 시 ui가 해상도에 따라 일그러지는게 신경쓰였다.
이를 어떻게 해결해야할까의 고민을 항상 해왔었고, 홈페이지 작업을 여러번 하고, 다른 사이트도 참고해보면서 이에 대한 해결책이 조금씩 나왔다.</p>
<h2 id="🧐-분석">🧐 분석</h2>
<p>지라, 노션 등 여러 페이지를 참고해보면, 브라우저 배율을 축소했을 때는 ui 변화가 없이 선형적으로 컴포넌트들이 줄어들었다.
그러나 확대를 할때는, ui 배치가 달라지거나, 글씨 크기, 컴포넌트 크기 등이 급격히 변하는 느낌을 보여주었다.</p>
<p>이 모습을 보고 내린 결론은 아래와 같다.</p>
<ol>
<li>&quot;하나의 특정 기준 해상도를 정하고, 그 해상도에서는 모두 <code>px</code> 또는 <code>퍼센트</code> 단위로 지정한다.&quot;</li>
</ol>
<ol start="2">
<li>기준 해상도 보다 작아질 경우, responsive하게 <code>vw</code>, <code>vh</code> 등의 단위를 활용하거나, ui배치 등을 다르게 하여 해당 해상도에 대응한다.</li>
</ol>
<p>내가 여기서 깨달은 가장 중요한 포인트는, 어느 순간부터는 <code>vw</code>,<code>vh</code>를 사용하지 않는 해상도가 있다는 점이다.</p>
<br/>

<h2 id="📱-about-기준-해상도">📱 About 기준 해상도</h2>
<p>왜 어느 순간부터는 vw,vh 를 사용하지 않을까? 그 어느 순간은 도대체 &quot;어느&quot; 순간일까?</p>
<p>내 생각에는 그 &quot;어느&quot; 순간은 모바일이나 태블릿이 아닌, 컴퓨터, 즉 <strong>랩탑이나 데스크탑</strong>으로 보는 순간이다.
그 순간 부터 <code>vw</code>, <code>vh</code>를 보지 않는 이유는, 사용자가 배율을 자유롭게 확대, 축소함에 따라 ui도 자연스럽게 확대 축소되게 하기 위함이라고 생각한다.</p>
<p><code>vw</code>,<code>vh</code> 단위를 사용하면, 기준이 모니터 그 자체이기 때문에, 확대와 축소를 해도 그 크기가 변하지 않는다.</p>
<p>그러나 브라우저에서 확대 축소를 하면 해상도가 변하는 것과 같아서, 같은 <code>30px</code>이어도 해상도가 높으면 작게보이고, 해상도가 크면 크게 볼 수 있는 것이다.</p>
<p>_(물론 너무 확대를 많이하게 되면 모바일 또는 태블릿의 해상도처럼 되어 <code>vw</code>, <code>vh</code>단위로 짜여진 ui가 보인다. 이에 대한 대응책은 아직 생각 중..)
_
모바일과 태블릿에서는 확대 축소가 해상도와 전혀 상관이 없기 때문에, <code>vw</code>, <code>vh</code>로 대응해도 상관없다.</p>
<p>그리고 모바일과 태블릿은 그 해상도가 너무도 다양하기 때문에 <code>vw</code>, <code>vh</code>로 대응해야만 여러 기기에서도 유사한 화면을 확인할 수 있을 것이다.</p>
<h2 id="✅-기준-해상도를-정하는-방법">✅ 기준 해상도를 정하는 방법</h2>
<p>그럼 기준 해상도는 몇으로 설정해야할까?</p>
<p>명확한 답은 아직 찾지 못했지만, 일반적인 경우에는 <code>1536*864</code> 또는 <code>1366*768</code>이 되지 않을까 싶다.
이 사이트 에 들어가면 국가별, 대륙별 또는 전세계의 모니터 해상도 사용자 비율을 볼 수 있다.</p>
<p>우리나라는 <code>1920*1080</code>을 가장 많이 쓰지만, 그보다 낮은 해상도인 <code>1536*864</code> 또는 <code>1366*768</code>를 기준으로 작업하면 얻을 수 있는 장점은 아래와 같다고 생각한다.</p>
<p><code>1920*1080</code>를 기준으로 작업하면 <code>1536*864</code> 또는 <code>1366*768</code>에서 ui가 일그러질 가능성이 있다.</p>
<p>그러나 <code>1536*864</code> 또는 <code>1366*768</code>에서 작업하게 되면, 이미 이 ui에서는 정상출력이 되므로, <code>1920*1080</code>에서는 당연히 정상 출력될 것이다!
(앞서 말했다시피 기준 해상도에서는 <code>vw</code>,<code>vh</code>를 안쓰니까 기준해상도보다 높은 해상도로 보면 기준해상도로 작업한 ui가 그대~로 축소된 형태가 된다.)</p>
<p>그래서 <code>1920*1080</code>보다 작은 해상도를 기준으로 작업하는게 좋다고 생각한다!</p>
<h2 id="🥰-느낀-점">🥰 느낀 점</h2>
<p>반응형에 대한 실마리를 조금씩 풀어나가고 있다는 생각이 든다. </p>
<p>아직 컴퓨터 화면에서 확대를 너무 많이 했을 때는 어떻게 효율적으로 대처를 해야할지는 잘 모르겠지만,</p>
<p>이번 프로젝트를 반응형으로 적용해가면서 또다른 깨달음을 얻을 수 있지 않을까 생각한다.</p>
<hr>
<blockquote>
<p>제 생각에 오류가 있거나, 더 나은 방법을 아신다면 꼭! 댓글로 남겨주시기 바랍니다! 감사합니다</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[비동기식 처리가 무엇인가요?😶  ]]></title>
            <link>https://velog.io/@c-jeongyyun/%EB%B9%84%EB%8F%99%EA%B8%B0%EC%8B%9D-%EC%B2%98%EB%A6%AC%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</link>
            <guid>https://velog.io/@c-jeongyyun/%EB%B9%84%EB%8F%99%EA%B8%B0%EC%8B%9D-%EC%B2%98%EB%A6%AC%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</guid>
            <pubDate>Sun, 14 Aug 2022 08:38:49 GMT</pubDate>
            <description><![CDATA[<h2 id="🤔비동기식-처리란">🤔비동기식 처리란?</h2>
<p>비동기식 처리는 특정 코드의 연산이 끝나기 전에 다른 코드를 실행시키는 작동시키는 자바스크립트의 특성을 말합니다. </p>
<h3 id="🙉-비유">🙉 비유</h3>
<p>비동기식 처리는 아래와 같은 상황에 빗댈 수 있습니다. 
오늘 내가 해야할 일이 <code>1. 이메일 보내기 2. 이메일 받기 3. 약속 준비하기</code> 라고 합시다.</p>
<p>만약 이것을 동기식 처리(비동기식 처리의 반대)로 진행한다면, 아래와 같이 진행됩니다. </p>
<blockquote>
<ol>
<li>이메일을 보낸다</li>
<li>이메일 답장이 올 때까지 기다린다. </li>
<li>이메일 답장이 오면 그제서야 약속 준비를 시작한다. </li>
</ol>
</blockquote>
<p>굉장히 비효율적이죠? 이메일 답장을 기다리는 것과 약속 준비하는 일은 꼭 그 순서를 지키지 않아도 되기 때문입니다. 만약 이메일 답장이 이틀 지나서 오게 된다면, 더 이상 약속을 준비하는게 의미가 없어지게 됩니다. </p>
<p>그럼 비동기식 처리로 진행한다면 어떻게 할 수 있는 걸까요? </p>
<blockquote>
<ol>
<li>이메일을 보낸다. </li>
<li><strong>이메일이 올 때까지 기다리면서, 약속 준비를 한다.</strong> </li>
<li>약속 준비를 하다가 이메일이 오면 이메일을 받는다. </li>
<li>약속 준비를 마저 한다. </li>
</ol>
</blockquote>
<p>비동기식 처리를 이용하면, 이메일 답장을 기다리는 시간을 낭비하지 않을 수 있습니다. 같은 일을 처리하더라도 훨씬 빠르게 처리할 수 있습니다.</p>
<h3 id="👩💻-비동기식-처리와-서버-api-통신">👩‍💻 비동기식 처리와 서버 API 통신</h3>
<p>비동기식 처리는 이러한 장점을 가지고 있기 때문에, 서버와 API통신을 할 때 비동기식 처리가 사용됩니다. </p>
<p>클라이언트는 서버에 필요한 정보가 있을 때 요청을 보내게 됩니다. 그럼 서버는 그 요청에 대한 내용들을 찾고, 찾은 정보를 다시 클라이언트로 보내게 됩니다. 그리고 클라이언트는, 서버에 필요한 정보를 보내고 받는 것 이외에도 페이지를 렌더링하는 등의 일을 해야합니다. </p>
<p>만약 이를 동기식 처리로 진행하게 된다면, </p>
<blockquote>
<ol>
<li>서버로 요청을 보내고</li>
<li>서버에서 정보를 보내줄 때까지 기다린다. </li>
<li>서버에서 정보를 보내주면, 그제서야 렌더링을 시작한다.</li>
</ol>
</blockquote>
<p>의 과정을 거치게 됩니다. </p>
<p>이러면 사용자는 빈 페이지를 바라보며 하염없이 기다리게 되겠죠...</p>
<p>그래서 우리는 API통신 시 비동기식 처리를 하게 됩니다. </p>
<blockquote>
<ol>
<li>서버로 요청을 보낸 뒤 </li>
<li><strong>서버로부터의 답변을 기다리는 동안 화면을 렌더링한다.</strong></li>
<li>서버로부터 답변이 오면 답변을 받는다. </li>
</ol>
</blockquote>
<p>서버로 부터 정보를 받는데 까지 걸리는 대기시간을 훨씬 효율적으로 사용하게 됩니다. 따라서, 비동기식 처리로 인해 사용자는 렌더링된 페이지를 좀더 빨리 볼 수 있습니다! 사용자가 지루하게 빈화면을 보는 시간을 줄일 수 있는 것이죠😀</p>
<p>어떠신가요, 비동기식 처리의 장점이 잘 느껴지나요?</p>
<h2 id="📌-요약-및-마무리">📌 요약 및 마무리</h2>
<p>지금까지 <code>비동기식 처리</code>에 대해 알아보았습니다!
비동기식 처리는 코드 실행을 하는 도중에 다른 코드를 실행할 수 있도록 하는 것을 의미하며, 서버와 API통신에 <code>비동기식 처리</code>를 적용하게 되면, 서버에게 정보 요청을 하는 코드를 실행하는 동안, 렌더링 등의 코드를 실행할 수 있습니다. </p>
<p>제가 말하고자 하는 바가 잘 전달되었길 바라면서 글을 마치겠습니다. 
감사합니다!</p>
<h2 id="참고-자료">참고 자료</h2>
<blockquote>
<ul>
<li><a href="https://velog.io/@unani92/Axios-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-%EB%B0%A9%EC%8B%9D">https://velog.io/@unani92/Axios-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-%EB%B0%A9%EC%8B%9D</a></li>
<li><a href="https://joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/">https://joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 - 짝지어 제거하기👯‍♀️]]></title>
            <link>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A7%9D%EC%A7%80%EC%96%B4-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A7%9D%EC%A7%80%EC%96%B4-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 28 Jul 2022 17:17:48 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💻출처 : 프로그래머스 &gt; 코딩 테스트 연습 &gt; 2017 팁스타운 &gt; <a href="https://school.programmers.co.kr/learn/courses/30/lessons/12973?language=javascript">짝지어 제거하기</a>
🏆난이도 : Level 2</p>
</blockquote>
<h2 id="📜-문제">📜 문제</h2>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/5599a201-6a79-4dc9-b09e-243e1bfd9c1b/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/5fd140ff-aea1-4053-8c3c-23f60f2f0dd0/image.png" alt=""></p>
<h3 id="📝-요약">📝 요약</h3>
<p>알파벳 소문자로 이루어진 문자열이 주어진다. 문자열에서 같은 알파벳이 붙어있다면, 그 둘을 제거한 뒤 앞뒤를 이어붙인다. 이 과정을 반복하여, 더이상 문자열을 제거할 수 없을 때 문자열이 남아있지 않은 상황이라면 <code>1</code>을, 문자열이 남아 있다면 <code>0</code>을 반환한다. </p>
<br/>

<hr>
<h2 id="🧠-문제-분석">🧠 문제 분석</h2>
<p>현재, 주어질 수 있는 문자열의 최대 길이는 <code>1,000,000</code>이다. 
따라서 직접 같은 알파벳이 두개가 붙어있는 부분을 찾고, 해당 부분을 지운 뒤 다시 처음부터 탐색하여 다시 동일한 알파벳 두개가 붙어있는 부분을 찾는 방식은 <strong>시간초과</strong>가 날 것이라고 생각하였다. </p>
<p>문자열을 지울 지의 여부는 현재 관찰하고 있는 문자의 앞뒤만 보고도 판단할 수 있다. 예컨데 <code>abbcc</code> 문자열에서 2번째 인덱스인 <code>b</code>를 관찰한다고 하였을 때, 2번째 인덱스에 인접한 인덱스, 즉, 인덱스 1번과 인덱스 3번만 관찰하면 된다. </p>
<p>또한, 짝지어진 알파벳을 제거한 후, 남은 문자열의 앞뒤를 이어붙여야 하기 때문에, 짝지어진 알파벳 이외에도 나머지 알파벳들을 알고 있어야 한다. </p>
<br/>

<hr>
<h2 id="💡-풀이-방법">💡 풀이 방법</h2>
<p>위의 분석을 통해, 이 문제에 가장 적합한 자료구조는 <code>stack</code>이라고 판단하였다. 
<img src="https://velog.velcdn.com/images/c-jeongyyun/post/b7e0af9c-1bdb-46cf-befd-9f2831cfe175/image.png" alt=""></p>
<p><code>stack</code>을 이용한다면, 현재 조회하는 문자와 인접한 문자를 <code>stack</code>의 <code>top</code>에서 쉽게 확인할 수 있으며, <code>pop</code>연산을 통해 문자 제거 및 이전 문자열과의 연결을 쉽게 구현할 수 있기 때문이다. </p>
<p>구체적인 구현방식은 아래와 같다. </p>
<ol>
<li>문자열을 맨 앞에서 부터 한 문자씩 순서대로 조회를 한다. </li>
<li>현재 조회한 문자가 <code>stack</code>의 <code>top</code>에 있는 문자와 동일하다면, <code>stack</code>에서 <code>pop</code>을 수행한다. (짝지어졌으므로 제거) </li>
<li>만약 현재 조회한 문자가 <code>stack</code>의 <code>top</code>에 있는 문자와 다르다면 <code>stack</code>에 저장한다. </li>
<li>문자열을 끝까지 조회한 뒤, <code>stack</code>에 문자가 남아있다면 0을 반환하고, <code>stack</code>에 문자가 남아있지 않다면 1을 반환한다. <blockquote>
<p><code>stack</code> 문자가 남아있다는 것은, 제거되지 않은 문자들이 있다는 것을 의미하기 때문이다. </p>
</blockquote>
</li>
</ol>
<br/>

<hr>
<h2 id="💻-코드">💻 코드</h2>
<p>위의 풀이과정을 코드로 구현하였다.
<code>stack</code>에 아무 것도 없는 경우는 조회할 <code>top</code>이 없기 때문에, 바로 조회한 문자를 <code>push</code>해주었다. </p>
<pre><code class="language-js">function solution(s)
{
    const length = s.length
    const stack =[]

    for(let i = 0; i&lt;length;i++){
        if(stack.length === 0) 
            stack.push(s[i])
        else
            stack[stack.length-1] === s[i] ? stack.pop() :  stack.push(s[i])
    }</code></pre>
<br/>

<hr>
<h2 id="🎤-느낀-점">🎤 느낀 점</h2>
<p><code>stack</code>을 떠올릴 수 있었다면 구현은 쉬웠던 문제라고 생각한다! 
좀 더 어려운 응용 문제를 풀기 위해, 어떤 상황에서 <code>stack</code>을 사용하면 되는지를 위주로 정리해보았던 문제였다 :) </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 - 오픈 채팅방💬]]></title>
            <link>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%98%A4%ED%94%88-%EC%B1%84%ED%8C%85%EB%B0%A9</link>
            <guid>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%98%A4%ED%94%88-%EC%B1%84%ED%8C%85%EB%B0%A9</guid>
            <pubDate>Fri, 22 Jul 2022 14:54:56 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💻출처 : 프로그래머스 &gt; 코딩 테스트 연습 &gt; 2019 KAKAO BLIND RECRUITMENT &gt; <a href="https://school.programmers.co.kr/learn/courses/30/lessons/62048">오픈 채팅방</a>
🏆난이도 : Level 2</p>
</blockquote>
<h2 id="📜-문제">📜 문제</h2>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/2c18a210-30fc-4918-bdd8-f5c5eeaf06b6/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/03c65a12-4ea0-42ab-bde0-9636231417e4/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/0ffa8f19-c3a7-4977-bc0a-adee764061f3/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/963f2cf9-b20b-427a-a774-f56093fb7d26/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/10cbf169-66d6-408f-ac6a-56eb35d27e1b/image.png" alt=""></p>
<h3 id="📝-요약">📝 요약</h3>
<p>사용자가 오픈 채팅방을 들어왔다 나갔다 할 수 있다. </p>
<p>사용자는 오픈 채팅방에 들어온 상태에서 닉네임을 바꿀 수 있고, 오픈 채팅방에 입장할 때도 닉네임을 바꿀 수 있다. 
오픈 채팅방에서 나가있는 상태에서는 닉네임을 바꿀 수 없다. </p>
<p>사용자가 오픈 채팅방에 들어올 때는 &quot;<code>닉네임</code>님이 들어왔습니다.&quot;라는 문구가 출력되고, 오픈 채팅방에서 나갈 때는 &quot;<code>닉네임</code>님이 나갔습니다.&quot;라는 로그가 출력된다. </p>
<p>닉네임의 경우 사용자들끼리 중복될 수 있으며, 닉네임을 변경한 경우 로그에 출력된 닉네임까지 모두 변경된다. </p>
<p>사용자들에게는 고유한 아이디가 부여된다. </p>
<p>사용자의 채팅방의 입장&amp;퇴장, 닉네임 변경 기록이 사용자의 아이디와 함께 주어진다. 입장과 닉네임 변경의 경우에는 닉네임도 함께 제공된다. </p>
<p>주어진 기록을 이용하여 최종적으로 출력될 로그를 구하시오. </p>
<br/>

<hr>
<h2 id="🧠-문제-분석">🧠 문제 분석</h2>
<p>결국은 사용자의 아이디에 해당하는 <code>최종적인 닉네임</code>만 알면 되는 문제이다. 
이 최종 닉네임을 구하는 방법으로 아래와 같은 방법들을 생각해보았다. </p>
<h3 id="💡아이디어-1---시간-초과">💡아이디어 1 - 시간 초과</h3>
<p>첫번째로는 <code>look-up table</code>을 만들어 보는 방식을 생각했다. </p>
<p>사용자가 채팅방에 들어오고 나가는 로그는 여러개 일 수 있는데, 사용자의 아이디에 따른 닉네임은 하나다. </p>
<p>왜냐하면, 우리는 사용자의 처음 닉네임, 두번째로 바꾼 닉네임.. 등의 히스토리가 필요한 것이 아니라, <code>최종 닉네임</code> 단 하나만 필요하기 때문이다. </p>
<p>따라서, 아래와 같이 테이블을 구성하여 문제를 풀고자 하였다. </p>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/ab30fa9d-2f79-4040-a645-733bae6d12af/image.png" alt=""></p>
<p>우선 문제에서 제공하는 기록을 조회하며 테이블들을 구성하였다. </p>
<p>기본적으로 <code>id</code>와 사용자의 <code>Enter</code>, <code>Leave</code> 정보는 왼쪽의 테이블에 저장하였다. </p>
<p>그리고 사용자의 닉네임을 바꿀 수 있는 <code>Enter</code>, <code>Change</code> 의 경우는 아래와 같은 두가지 상황에 따라 다르게 대처하였다. </p>
<ul>
<li>오른쪽에 있는 테이블에 <code>id</code>가 있는 경우: <code>닉네임</code> 변경 </li>
<li>오른쪽에 있는 테이블에 <code>id</code>가 없는 경우: <code>id</code>와 <code>닉네임</code>을 테이블에 새로 추가 </li>
</ul>
<p>위와 같은 규칙으로 최종적인 테이블을 구성하였다면, 
왼쪽 테이블의 <code>id</code>와 <code>state</code>를 하나씩 읽으며, 오른쪽의 <code>look-up 테이블</code>에서 사용자의 <code>id</code>에 대응하는 닉네임을 조회하여 찾고자 하였다.</p>
<p>이를 구현한 코드는 아래와 같다. </p>
<h4 id="코드">코드</h4>
<pre><code class="language-js">function solution(record) {
    idAndState =[]
    idAndNickname=[]

    record.forEach((r)=&gt;{
        let info = r.split(&quot; &quot;)
        const state = info[0]
        const id = info[1]
        const nickname = info[2]


        if(state===&quot;Change&quot; || state==&quot;Enter&quot;){
            const index = idAndNickname.findIndex((idNick)=&gt;idNick[0]===id)
            if(state===&quot;Change&quot;){
                idAndNickname[index] = [id,nickname]
            }else{
                if(index===-1){
                    idAndNickname.push([id,nickname])
                }else{
                    idAndNickname[index] = [id,nickname]
                }
            }
        }

        if(state==&quot;Enter&quot; || state==&quot;Leave&quot;){
            idAndState.push([id,state])
        }

    })

    var answer = [];

    idAndState.forEach((idState)=&gt;{
        const nickname = idAndNickname.find((idNick)=&gt; idNick[0] === idState[0])[1]

        if(idState[1] == &quot;Enter&quot;){
            answer.push(`${nickname}님이 들어왔습니다.`)
        }else{
            answer.push(`${nickname}님이 나갔습니다.`)
        }
    })

    return answer;
}
</code></pre>
<p>이 코드의 결과는 실패다😅</p>
<p>코드를 짜면서도 걱정했었던 <code>시간 초과</code>가 발생했기 때문이다.</p>
<p>테이블 만들면서도 오른쪽 테이블에서 해당 <code>id</code>가 존재하는지 여부를 알기위해<code>id</code>로 <code>검색 연산</code>을 하고, 출력 로그들을 생성할 때도 오른쪽 테이블에서 <code>id</code>로 <code>닉네임</code> 검색 연산을 하니...시간을 안초과할수야 없겠더라. </p>
<p>그래도 도무지 아이디어가 나오지 않아 구글링을 하였다. </p>
<br/>

<hr>
<h3 id="💡아이디어2---map-사용✨">💡아이디어2 - Map 사용✨</h3>
<p>구글링을 통해 얻은 것은 바로 <code>Map</code> 자료구조이다!</p>
<p><code>Map</code> 자료구조는 <code>key</code>값과 <code>value</code> 값으로 구성되어 있고, 검색속도가 아주 빠르다는 특징을 가지고 있다. </p>
<p>검색 속도가 빠른 이유는, <code>key</code>값을 <code>hashing</code> 한 결과를 <code>인덱스</code> 값으로 사용하기 때문이다. </p>
<p>간단히 말하자면, <code>key</code> 자체를 배열의 <code>인덱스</code>로 사용하는 자료구조라고 생각하면 된다.</p>
<p>그렇기에, <code>key</code>값을 알고 있으면, 그에 대응하는 <code>value</code>를 아주 빠르게 조회할 수 있다. </p>
<p>현재 <a href="https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%98%A4%ED%94%88-%EC%B1%84%ED%8C%85%EB%B0%A9#%EC%95%84%EC%9D%B4%EB%94%94%EC%96%B4-1---%EC%8B%9C%EA%B0%84-%EC%B4%88%EA%B3%BC">아이디어 1</a>을 참고해보았을 때, 우리는 <code>id</code>에 대응하는 <code>닉네임</code>을 찾고자 하며, 조회에 시간이 오래걸리는 문제가 있었다. </p>
<p>여기에 <code>Map</code> 구조를 사용하면, <code>id</code>는 <code>key</code>에 대응시키고 <code>닉네임</code>는 <code>value</code>에 대응시킬 수 있으며, <code>Map</code> 구조의 특성 덕분에 실행 속도도 줄일 수 있다.  </p>
<p>이를 구현한 코드는 아래와 같다. </p>
<br/>
---

<h2 id="💻-코드">💻 코드</h2>
<pre><code class="language-js">function solution(record) {
    const idAndState =[]
    const idAndNickMap = new Map();

    record.forEach((r)=&gt;{
        const [state,id,nickname] = r.split(&quot; &quot;);

        if (state !== &quot;Change&quot;){
            idAndState.push([id,state])
        }

        if(nickname){
            idAndNickMap.set(id,nickname);
        }

    })

    var answer = [];

    idAndState.forEach((idState)=&gt;{
        const [id,state] = idState;
        const nickname = idAndNickMap.get(id)

        if(state == &quot;Enter&quot;){
            answer.push(`${nickname}님이 들어왔습니다.`)
        }else{
            answer.push(`${nickname}님이 나갔습니다.`)
        }
    })

    return answer;
}</code></pre>
<hr>
<h2 id="🎤-느낀-점">🎤 느낀 점</h2>
<p>머릿속 깊은 곳에 있는 <code>Map</code>을 다시 꺼내올 수 있었던 문제였다. 
현재 문제에 가장 적합한 자료구조를 생각해내는 것도 중요한 요소라는 생각이 들었다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 - 멀쩡한 사각형 🟨]]></title>
            <link>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%A9%80%EC%A9%A1%ED%95%9C-%EC%82%AC%EA%B0%81%ED%98%95</link>
            <guid>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%A9%80%EC%A9%A1%ED%95%9C-%EC%82%AC%EA%B0%81%ED%98%95</guid>
            <pubDate>Thu, 14 Jul 2022 19:03:03 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💻출처 : 프로그래머스 &gt; 코딩 테스트 &gt; Summer/Winter Coding(2019) &gt; <a href="https://school.programmers.co.kr/learn/courses/30/lessons/62048">멀쩡한 사각형</a>
🏆난이도 : Level 2</p>
</blockquote>
<h2 id="📜-문제">📜 문제</h2>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/8101c8d9-0a53-46ad-8525-21132a7e9998/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/91b2a270-f5d3-4628-adf0-091e1c6f505e/image.png" alt=""><img src="https://velog.velcdn.com/images/c-jeongyyun/post/fd8d603c-e7a3-4a29-b63e-678d82d51542/image.png" alt=""></p>
<h3 id="📝-요약">📝 요약</h3>
<p>직사각형 종이를 대각선으로 자르면 두 개의 직각삼각형이 생긴다. 
이 두개의 직각 삼각형에서 얻을 수 있는 1cm*1cm 크기의 정사각형 개수를 구하여라. 단, 각 정사각형의 가로, 세로는 원래 종이의 가로, 세로 방향과 평행해야 한다.<br> <br/></p>
<hr>
<h2 id="💡-아이디어-1---owh">💡 아이디어 1 - O(WH)</h2>
<p>직사각형을 대각선 방향으로 자르면 크기가 똑같은 직각 삼각형 두 개를 얻을 수 있다. 그럼 직각 삼각형 하나에 들어있는 정사각형 개수만 알면 되겠군! </p>
<p>따라서, 직각 삼각형에 정사각형을 그린 후, 해당 정사각형이 직각 삼각형 내부에 모두 포함되어있는지 판단하였다. </p>
<p>이를 판단하기 위해, 직각 삼각형을 아래 그림과 같이 모눈위에 올려놓았다. </p>
<img src = "https://velog.velcdn.com/images/c-jeongyyun/post/dcbe097e-0cd1-4219-9e12-50321b9567ea/image.jpg" width="400px">

<p>노란색 선을 직선의 방정식으로 표현한 뒤, 정사각형의 오른쪽 위 꼭짓점을 직선의 방정식에 대입해, 결과가 음수인지 양수인지에 따라 하늘색 영역에 포함되는지 여부를 판단하였다. </p>
<p>그럼 정사각형의 오른쪽 위 꼭짓점을 기준으로 본다고 정했으니까, <code>(1,1)</code> 있는 정사각형을 시작으로 <code>for 문</code>을 돌리면서, 하늘색 영역을 벗어날 때까지 사각형의 <code>x좌표</code>를 하나씩 증가시키면 되겠네? 만약 하늘색 영역을 벗어나면 <code>y좌표</code>를 증가시켜서 그 윗줄에 포함된 정사각형 개수를 구하면 되고! </p>
<p>아, 그런데 문제의 조건을 다시보자. <code>w</code>, <code>h</code> 의 범위는 <strong>1억 이하의 자연수</strong>이다. </p>
<p>...</p>
<blockquote>
<p><em>이렇게 풀면 무조건 시간 초과다</em></p>
</blockquote>
<p>그래서 문제를 다시 읽었더니 예시의 그림이 눈에 들어왔다. 
<img src="https://velog.velcdn.com/images/c-jeongyyun/post/93bfe53f-a881-4c65-9938-e27f8cd26da9/image.png" width="300px"/></p>
<p>그림에서 약간의 힌트를 주고 있었다. 
아, 대각선 부분에 걸쳐있는 사각형 개수만 구하면 되네! 
그래서 아래의 방법을 생각하였다. </p>
<h2 id="💡-아이디어-2---실제-풀이✅">💡 아이디어 2 - 실제 풀이✅</h2>
<p>이 방식은 컴퓨터 그래픽스의 rasterization 단계에서 사용하는 DDP 알고리즘과 유사하다. (수업 때 배운 걸 드디어 써먹는구나) </p>
<p>DDP 알고리즘의 경우, 대각선의 방향을 따라가며 대각선을 포함하는 정사각형을 찾는 알고리즘이다. 나는 DDP 알고리즘처럼 아래와 같은 규칙을 찾아보았다. </p>
<p>우선, 문제에서 준 예시와 달리 아래와 같이 사각형을 두고 생각하였다. (개인 취향) 
<img src="https://velog.velcdn.com/images/c-jeongyyun/post/54e7b16d-1412-4d12-8ea3-dd37ba844db6/image.jpg" alt=""></p>
<p>이 사진을 보면, <code>대각선 위에 존재하는 정사각형</code>의 옆이나 위, 그리고 대각선 위치(<code>우상향 방향</code>)에, <code>대각선 위에 있는 다른 정사각형</code>이 존재한다는 것을 알 수 있다.  </p>
<p>따라서, 정사각형의 오른쪽 위의 좌표가 <code>(1,1)</code>인 정사각형을 시작점으로 대각선을 따라 <code>우상향 방향</code>에 있는 정사각형을 보고, 대각선 위에 있는 정사각형의 특징을 알아냈다. </p>
<p>직사각형의 대각선의 기울기를 <code>m</code>이라고 하자.</p>
<p>현재 정사각형의 오른쪽 위 좌표를 <code>(x,y)</code> 라 했을 때, 
<code>w &gt; h</code> 인 직사각형에서는 </p>
<ul>
<li><code>x/y &lt; m</code>이라면 현재 정사각형의 <code>오른쪽 정사각형</code>도 대각선에 포함되고, </li>
<li><code>x/y &gt; m</code> 이면, 현재 정사각형의 <code>위쪽 정사각형</code>이 대각선에 포함되며,</li>
<li><code>x/y == m</code> 이면, 현재 정사각형의 <code>오른쪽 위 대각선에 있는 정사각형</code>이 대각선에 포함된다. </li>
</ul>
<p>따라서, 나는 이러한 규칙을 이용하여 정사각형의 오른쪽 위의 좌표가 <code>(1,1)</code>인 정사각형을 시작점으로, 대각선 위에 있는 정사각형들의 개수를 모두 구했고, 전체 정사각형 개수에는 이를 제외하여 최종 결과를 얻었다. </p>
<blockquote>
<p><strong>참고 ❗</strong>
<code>w &lt; h</code> 인 경우는 규칙이 살짝 달라진다.
그러나, 위에 내용을 이해했다면 충분히 규칙을 찾을 수 있을 것이다. 
직접 그려서 규칙을 찾으면 이해가 쉽다! </p>
</blockquote>
<br/>
---
## 💻 코드
코드에서는 `w < h` 인 경우는 죄다 `w > h`로 변경하여 규칙을 통일해주었다. 
풀이 코드는 아래와 같다. 

<pre><code class="language-js">function solution(width, height) {
    var answer = 1;
    let w = width;
    let h = height;

    if(w &lt; h){ // 규칙 통일을 위해 w &lt; h 인 경우, w &gt; h로 변경 
        w = height;
        h = width;
    }

    const m  = w/h;  // 기울기

    let x=1; // 정사각형 시작 좌표 
    let y=1;

    let count =0; // 대각선 위에 놓여 있는 정사각형 개수 

    while (x !== w || y !== h){
        count++;

        // 현재 정사각형의 위에 있는 정사각형이 대각선 위의 정사각형 
        if(m &lt; x/y){ 
            y++;
            continue;
        }

          // 현재 정사각형의 대각선에 있는 정사각형이 대각선 위의 정사각형 (아래의 x++ 까지 실행함)
        if(m == x/y) y ++;

        x++; // if 문 모두 실행 안되는 경우 - 현재 정사각형의 오른쪽에 있는 정사각형이 대각선 위의 정사각형 
    }

    count ++ ; // 최 우상단에 있는 정사각형 세어주기 
    answer = w*h - count;

    return answer;
}
</code></pre>
<h2 id="🎤-느낀-점">🎤 느낀 점</h2>
<p>야심차게 생각했던 첫번째 아이디어는 무용지물이었다. 
처음부터 문제의 조건과 예시를 주의 깊게 살펴보았다면, 허비되는 시간을 줄일 수 있었을 것이다😥 </p>
<blockquote>
<p>*<em>📌 결론 *</em> : 어떤 문제든 간에 문제를 잘 살펴보도록 하자! </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Eslint 관련 오류 해결하기 ]]></title>
            <link>https://velog.io/@c-jeongyyun/React-Eslint-%EA%B4%80%EB%A0%A8-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@c-jeongyyun/React-Eslint-%EA%B4%80%EB%A0%A8-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 11 Jul 2022 03:52:01 GMT</pubDate>
            <description><![CDATA[<h2 id="첫번째-오류">첫번째 오류</h2>
<h3 id="🔥-오류-내용">🔥 오류 내용</h3>
<pre><code>ERROR in [eslint] Plugin &quot;react&quot; was conflicted between 
&quot;package.json » eslint-config-react-app » C:\choi\SideProjects\oneNth\1-n-web-frontend\node_modules\eslint-config-react-app\base.js&quot; 
and 
&quot;BaseConfig » C:\choi\SideProjects\oneNth\1-n-Web-Frontend\node_modules\react-scripts\node_modules\eslint-config-react-app\base.js&quot;</code></pre><p>리액트를 쓰면서 이런 오류는 처음봤다. 
<code>yarn start</code>로 프로젝트를 실행시키면 이렇게 오류가 등장하고, <code>package.json</code>을 <code>ctrl+s</code> 로 저장하면 정상 실행되는... 그런 오류였다. 
<br/></p>
<h3 id="🚿-해결-방법">🚿 해결 방법</h3>
<p>구글링을 한 결과, <code>casing</code> 문제, 즉, 대소문자 문제라고 하였다. 
위의 오류에서 파일 경로가 두개 나와있는데, 잘 보면 첫번째 경로에는 <code>1-n-web-frontend</code>로 되어있고 두번째 경로에는 <code>1-n-Web-Frontend</code>라고 되어있다. 대소문자가 다르다. </p>
<p>이건 윈도우 환경에서 발생하는 문제인데, 이전 버전의 리액트는 대소문자 구분 없이 경로를 찾았지만 업데이트 후 변경된 모양이다. </p>
<p>현재 저장된 형태는 <code>1-n-Web-Frontend</code>이었기 때문에, 이를 <code>1-n-web-frontend</code> 로 변경해주었다. </p>
<p>그래서 이 오류는 해결!✨</p>
<br/>

<hr>
<h2 id="두번째-오류">두번째 오류</h2>
<h3 id="🔥-오류-내용-1">🔥 오류 내용</h3>
<p>첫번째 오류를 해결했더니 모든 컴포넌트에 대해 아래와 같은 오류들이 발생하였다. </p>
<pre><code> Parsing error: require() of ES Module C:\choi\SideProjects\oneNth\1-n-web-frontend\node_modules\eslint\node_modules\eslint-scope\lib\definition.js 
 from C:\choi\SideProjects\oneNth\1-n-web-frontend\node_modules\babel-eslint\lib\require-from-eslint.js not supported.

Instead change the require of definition.js in 
C:\choi\SideProjects\oneNth\1-n-web-frontend\node_modules\babel-eslint\lib\require-from-eslint.js 
to a dynamic import() which is available in all CommonJS modules</code></pre><p>역시 구글링... </p>
<br/>

<h3 id="🚿-해결-방법-1">🚿 해결 방법</h3>
<p>이 오류의 원인은 deprecated된 <a href="https://github.com/babel/babel-eslint">babel-eslint</a>를 사용하려했기 때문이었다. 현재 <code>babel-eslint</code>는 <code>@babel/eslint-parser</code>로 옮겨졌다. </p>
<p>따라서, <code>package.json</code> 파일의 </p>
<pre><code class="language-json">babel-eslint&quot;: &quot;^10.0.2</code></pre>
<p>부분을, </p>
<pre><code class="language-json">@babel/eslint-parser&quot;: &quot;^7.5.4&quot;</code></pre>
<p>로 수정해주었다. </p>
<p>그 후, 터미널에서 <code>yarn install</code>을 실행하였다. (npm의 경우 <code>npm i</code>)</p>
<p>그후 다시 <code>yarn start</code>로 프로젝트를 실행해보았더니, 컴포넌트마다 발생했던 오류는 모두 사라지고 아래와 같은 오류가 등장했다. </p>
<pre><code class="language-terminal">[eslint] Failed to load parser &#39;babel-eslint&#39; declared in 
&#39;package.json » eslint-config-react-app » C:\choi\SideProjects\oneNth\1-n-web-frontend\node_modules\eslint-config-react-app\base.js&#39;: 
Cannot find module &#39;babel-eslint&#39;
Require stack:
- C:\choi\SideProjects\oneNth\1-n-web-frontend\node_modules\eslint-config-react-app\base.js</code></pre>
<p>오류 내용을 보면 현재 <code>node_modules\eslint-config-react-app\base.js</code> 에서 <code>babel-eslint</code>를 못찾고 있다는 것을 알 수 있다. </p>
<p>우리는 <code>babel-eslint</code>를 쓸 것이 아니기 때문에, 
<code>node_modules\eslint-config-react-app\base.js</code> 파일을 열어서 </p>
<pre><code class="language-js">parser: &#39;babel-eslint&#39;,</code></pre>
<p>라고 적혀있는 부분을, </p>
<pre><code class="language-js"> parser: &quot;@babel/eslint-parser&quot;,</code></pre>
<p>로  변경해주었다. </p>
<br/>
그랬더니 오류 완전히 해결💖! 

<br/>

<hr>
<h2 id="느낀-점">느낀 점</h2>
<p>구글링으로 해결할 수 있는 문제라서 정말 다행이었다...ㅎㅎ
프로젝트 설정 관련해서도 신경쓸게 꽤 있다는 것을 다시금 체감한 하루였다 😛</p>
<br/>

<hr>
<blockquote>
<p><strong>출처🔖</strong></p>
<ul>
<li>첫번째 오류 해결 방법 : <a href="https://stackoverflow.com/questions/70377211/error-when-deploying-react-app-and-it-keeps-sayings-plugin-react-was-confli">stackOverFlow</a></li>
<li>두번째 오류 해결방법 : <a href="https://stackoverflow.com/questions/69554485/eslint-error-must-use-import-to-load-es-module">stackOverFlow</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 피로도 - JavaScript ]]></title>
            <link>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%94%BC%EB%A1%9C%EB%8F%84-JavaScript</link>
            <guid>https://velog.io/@c-jeongyyun/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%94%BC%EB%A1%9C%EB%8F%84-JavaScript</guid>
            <pubDate>Thu, 07 Jul 2022 10:42:48 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💻<strong>출처</strong> : 프로그래머스 &gt; 코딩 테스트 &gt; <a href="https://school.programmers.co.kr/learn/courses/30/lessons/87946">위클리 챌린지</a> 
🏆<strong>난이도</strong> : Level 2</p>
</blockquote>
<h2 id="📜문제">📜문제</h2>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/90d1d6f7-118a-490d-88cc-9f2a2e36c1dd/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/c-jeongyyun/post/d965f316-1230-4db4-bc54-9018078d5759/image.png" alt=""></p>
<h4 id="요약">요약</h4>
<p>게임에는 여러 던전이 있다. 
던전을 플레이하기 위해서는, 플레이어의 피로도가 던전에 할당된 <code>최소 피로도</code> 이상이어야 한다. 
플레이어가 던전을 플레이한 이후, 플레이어의 피로도는 던전의 <code>소모 피로도</code>만큼 감소한다. 
사용자가 탐험할 수 있는 던전의 최대 개수를 출력하라. </p>
<br/>


<h2 id="🔑-풀이">🔑 풀이</h2>
<p>사용자가 어떤 순서로 던전을 탐험하느냐에 따라 탐험할 수 있는 최대 던전의 수가 달라진다. 
예시를 살펴보았을 때, 던전의 <code>최소 피로도</code>와 <code>소모 피로도</code>에 따른 탐색 순서에는 특별한 규칙이 없어보인다. 
따라서, 가능한 던전의 모든 배열 순서(순열)를 탐색하여 사용자가 탐험할 수 있는 최대 던전의 수를 구하였다. </p>
<p>던전들의 모든 배열 순서는 <code>DFS</code>를 응용하여 구현하였다. </p>
<br/>

<h2 id="💻-코드">💻 코드</h2>
<pre><code class="language-js">function solution(k, dungeons) {
    let max=0;
    const visited = Array(dungeons.length).fill(false)

    function dfs(count,k){
        max = max &lt; count ? count : max;
        for(let i=0;i &lt; dungeons.length;i++){
            if(visited[i])
                continue;

            let curDungeon= dungeons[i]
            if(curDungeon[0]&lt;=k){
                visited[i]=true;
                dfs(count+1, k-curDungeon[1])
                visited[i]=false;
            }
        }

    }

    dfs(0,k)
    return max;
}</code></pre>
<br/>

<h2 id="🎤-느낀-점">🎤 느낀 점</h2>
<p>간단한 코드지만 오랜만에 <code>DFS</code>를 구현하였더니 좀 막막한 구석이 있었다. 
문제를 꾸준히 풀어 이런 낯섦을 빨리 없애야 겠다😥</p>
]]></description>
        </item>
    </channel>
</rss>