<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>edwin_.log</title>
        <link>https://velog.io/</link>
        <description>혼자 하는 개발은 없다고 생각하는 개발자</description>
        <lastBuildDate>Tue, 18 Mar 2025 05:25:25 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>edwin_.log</title>
            <url>https://velog.velcdn.com/images/edwin_/profile/f322c003-873c-4f45-8141-64cc1344ceb9/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. edwin_.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/edwin_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[카카오테크 부트캠프 2기 제주 중간 후기]]></title>
            <link>https://velog.io/@edwin_/%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%85%8C%ED%81%AC-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-2%EA%B8%B0-%EC%A0%9C%EC%A3%BC-%EC%A4%91%EA%B0%84-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@edwin_/%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%85%8C%ED%81%AC-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-2%EA%B8%B0-%EC%A0%9C%EC%A3%BC-%EC%A4%91%EA%B0%84-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Tue, 18 Mar 2025 05:25:25 GMT</pubDate>
            <description><![CDATA[<p>카카오테크 부트캠프 제주 중간 후기</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/3d5072de-b894-41f1-b34b-ff1d7e5a9121/image.JPG" alt="">
<img src="https://velog.velcdn.com/images/edwin_/post/fbea7d17-a26e-4a61-bc55-56f468776a8d/image.JPG" alt="">
<img src="https://velog.velcdn.com/images/edwin_/post/3da86383-5ca8-4792-9368-9a7ad688e2d0/image.JPG" alt=""></p>
<p>카카오테크 부트캠프 제주 중간 후기</p>
<p>이번에 카카오테크 부트캠프 제주 과정에 참여하게 되어 벌써 중반을 넘어 개발 단계에 접어들었다. 총 6개월간 진행되는 이 과정은 4개월의 온라인 교육과 2개월의 제주도 오프라인 합숙으로 구성되어 있는데 특히 제주도 합숙 과정에서의 몰입도가 매우 인상적이다.</p>
<p>교육 프로그램은 클라우드 기반의 최신 기술들을 중심으로 구성되어 있으며 실무적이고 현장감 있는 교육 방식 덕분에 실력 향상에 큰 도움이 되고 있다. 특히 구름톤이라는 해커톤 이벤트가 정말 기억에 남았다.</p>
<p>해커톤 이후 2개월 동안 우리 팀이 직접 프로덕트를 개발하여 실제로 출시하고 이후 홍보하고 운영까지 이어지는 전 과정을 경험할 수 있다는 점이 매우 매력적이다. 단순히 개발 능력뿐 아니라 제품 기획부터 출시 운영까지의 전 과정을 체계적으로 경험하며 스타트업이 실제로 겪는 모든 프로세스를 이해할 수 있다는 것이 가장 큰 장점 중 하나라고 생각한다.</p>
<p>이 과정에서 특히 좋았던 점을 몇 가지 언급하자면 우선 교육을 담당하는 Void 강사가 항상 학생들의 질문에 친절하게 답변해주시고 꼼꼼하게 피드백을 주셔서 정말 많은 도움이 되고 있다. Void 강사의 수업 덕분에 복잡한 클라우드 개념들도 쉽게 이해하고 실습할 수 있었다.</p>
<p>또한 제공되는 수업 교재 역시 매우 우수하다. 클라우드 기술의 개념부터 심화된 실습 내용까지 체계적으로 구성되어 있어서 수업 외에도 개인적으로 학습할 때 큰 도움이 되고 있다. 교재가 단순히 이론적인 설명에서 끝나는 것이 아니라 실습 중심의 사례들과 함께 구성되어 있어서 수업 내용을 직접 구현해보고 복습하는 데에도 최적의 자료다.</p>
<p>교육 진행을 맡고 있는 스타트업코드라는 교육 스타트업으로부터 외주를 받아 진행되는 방식 또한 매우 신선하고 좋았다. 스타트업 특유의 실무 중심적이고 실용적인 교육 방식 덕분에 단순 이론 습득을 넘어 실제 현장에서 즉각 활용 가능한 능력을 기를 수 있었다.</p>
<p>마지막으로 강의를 맡고 있는 Jeff 강사의 열정과 적극적인 태도에 큰 동기부여를 받고 있다. Jeff 강사의 성실하고 꾸준한 노력을 보며 나 또한 더욱 최선을 다하게 되었고 함께 성장하는 느낌을 받을 수 있어 매우 좋았다. 그리고 Leo 강사 또한 강의를 매우 잘 해주시고 항상 수업 분위기를 즐겁게 만들어 주셔서 수업 시간이 더욱 기대가 되었다.</p>
<p>아직 과정이 마무리된 것은 아니지만 개발 단계를 진행하면서 앞으로 남은 제주도 합숙 생활에서 더욱 성장할 수 있을 것이라는 기대가 크다. 지금까지의 경험만으로도 이 부트캠프에 참여한 것은 정말 탁월한 선택이었다고 생각한다.</p>
<p>#카카오 #kakao #카카오테크부트캠프 #카테부 #카테부커뮤니티 #kakaotechbootcamp #KTB #부트캠프 #부트캠프추천 #제주부트캠프 #제주 #클라우드#goorm #한국전파진흥협회</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[쿼리 최적화, 어떻게 최적화 할 수 있을까?]]></title>
            <link>https://velog.io/@edwin_/%EC%BF%BC%EB%A6%AC-%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@edwin_/%EC%BF%BC%EB%A6%AC-%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Sat, 23 Nov 2024 10:43:26 GMT</pubDate>
            <description><![CDATA[<p>데이터베이스를 사용하다 보면 동일한 쿼리라도 어떻게 작성하고 최적화하느냐에 따라 처리 시간이 몇 초에서 몇 시간까지 크게 달라질 수 있습니다. 이번 글에서는 쿼리 최적화의 개념부터 구현 방식, 그리고 성능 향상을 위한 다양한 팁까지 상세히 알아보겠습니다. 🧐</p>
<h2 id="쿼리-최적화란-🚀">쿼리 최적화란? 🚀</h2>
<p><strong>쿼리 최적화(Query Optimization)</strong>는 관계형 데이터베이스(RDB), NoSQL, 그래프 데이터베이스 등 다양한 데이터베이스 시스템에서 사용되는 기능으로, 주어진 쿼리를 가장 효율적으로 실행할 수 있는 방법을 찾는 과정입니다. 쿼리 최적화 프로그램은 여러 가능한 쿼리 실행 계획 중에서 비용이 가장 낮은 계획을 선택하여 데이터베이스의 성능을 향상시킵니다.</p>
<h3 id="쿼리-최적화의-중요성">쿼리 최적화의 중요성</h3>
<p>동일한 쿼리라도 어떤 실행 계획을 선택하느냐에 따라 처리 시간은 몇 초에서 몇 시간까지 크게 차이날 수 있습니다. 모든 가능한 쿼리 계획 중 최상의 것을 찾는 것은 매우 복잡하고 시간이 많이 소요되기 때문에, 일반적으로는 합리적인 시간 내에 충분히 좋은(near-optimal) 계획을 찾는 것이 목표입니다.</p>
<h2 id="쿼리-최적화-시-고려해야-할-요소들-📝">쿼리 최적화 시 고려해야 할 요소들 📝</h2>
<h3 id="1-물리적-리소스-⚙️">1. 물리적 리소스 ⚙️</h3>
<p>I/O 연산: 디스크 접근 횟수를 최소화하여 성능을 향상시킵니다.
디스크 버퍼 공간: 충분한 버퍼 공간을 활용하여 데이터를 효율적으로 읽고 씁니다.
CPU 경로 길이: CPU 연산을 최적화하여 처리 시간을 단축합니다.
병렬 처리: 멀티코어 및 다중 프로세서를 활용하여 작업을 병렬로 수행합니다.</p>
<h3 id="2-액세스-방법-🔍">2. 액세스 방법 🔍</h3>
<ul>
<li>기본 인덱스 액세스: 프라이머리 키를 통한 빠른 데이터 검색.</li>
<li>보조 인덱스 액세스: 보조 인덱스를 활용하여 검색 속도 향상.</li>
<li>전체 스캔(Full Scan): 인덱스가 없을 경우 테이블의 모든 행을 검사.</li>
</ul>
<h3 id="3-조인-방법-🔗">3. 조인 방법 🔗</h3>
<ul>
<li>중첩 루프 조인(Nested Loops Join): 작은 테이블을 기반으로 큰 테이블과 조인.</li>
<li>해시 조인(Hash Join): 해시 함수를 사용하여 조인 키를 매칭.</li>
<li>병합 조인(Merge Join): 조인 대상 테이블이 정렬되어 있을 때 효율적.</li>
<li>카티전 프로덕트 조인(Product Join): 모든 가능한 행의 조합을 생성(비효율적).</li>
</ul>
<h3 id="4-조인-순서-🔄">4. 조인 순서 🔄</h3>
<p>조인 순서는 쿼리의 성능에 직접적인 영향을 미칩니다. 예를 들어, 각기 다른 크기의 테이블 A(10행), B(10,000행), C(1,000,000행)를 조인할 때, 먼저 B와 C를 조인하면 큰 데이터셋을 처리해야 하므로 시간이 오래 걸립니다. 반면에 A와 C를 먼저 조인하면 작은 테이블과 큰 테이블을 조인하므로 상대적으로 효율적입니다.</p>
<h2 id="쿼리-최적화의-유형">쿼리 최적화의 유형</h2>
<h3 id="논리적-최적화">논리적 최적화</h3>
<p>정의: 쿼리를 해결하기 위해 관계 대수(Relational Algebra) 시퀀스를 생성하는 과정입니다.
목적: 쿼리의 구조를 재작성하여 보다 효율적인 실행이 가능하도록 합니다.
예시: 조건 푸시다운, 중복 제거, 불필요한 조인 제거 등.</p>
<h3 id="물리적-최적화">물리적 최적화</h3>
<p>정의: 각 작업을 실제로 어떻게 수행할지 결정하는 과정입니다.
목적: 최적의 실행 계획을 선택하여 리소스 사용을 최소화합니다.
예시: 인덱스 사용 여부 결정, 조인 알고리즘 선택, 병렬 처리 적용 등.</p>
<h2 id="쿼리-최적화의-구현-방법">쿼리 최적화의 구현 방법</h2>
<p>쿼리 계획 트리</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/ac5ca56e-4570-4c99-885e-a2c63c3f71cc/image.png" alt=""></p>
<p>쿼리 실행 계획은 <strong>“계획 노드”</strong>의 트리 구조로 표현됩니다.
계획 노드: 쿼리를 실행하는 데 필요한 단일 작업을 캡슐화합니다.
데이터 흐름: 트리의 하단에서 상단으로 결과가 전달됩니다.
노드 관계: 자식 노드의 결과가 부모 노드의 입력으로 사용됩니다.</p>
<p>계획 노드의 종류</p>
<ul>
<li>조인 노드: 두 개의 자식 노드를 가지며, 각각 조인할 테이블이나 결과셋을 나타냅니다.</li>
<li>정렬 노드(Sort Node): ORDER BY, DISTINCT, GROUP BY 등의 연산을 수행하며 하나의 자식 노드를 가집니다.</li>
<li>리프 노드(Leaf Node): 실제 데이터를 읽어들이는 노드로, 인덱스 스캔이나 순차적 스캔을 수행합니다.</li>
</ul>
<h2 id="인덱싱-기법">인덱싱 기법</h2>
<p>데이터베이스에서 인덱싱은 쿼리 성능에 매우 중요한 역할을 합니다. 일반적으로 B-트리 인덱스가 가장 많이 사용되지만, 경우에 따라서는 비트맵 인덱스가 더 효율적일 수 있습니다.</p>
<h3 id="b-트리-인덱스">B-트리 인덱스</h3>
<ul>
<li>특징: 균형 잡힌 트리 구조로, 검색, 삽입, 삭제 연산의 시간 복잡도는 O(log N)입니다.</li>
<li>장점: 범위 검색 및 순차적인 데이터 접근에 효율적입니다.</li>
<li>사용 사례: 고유한 값이 많고 데이터 변경이 빈번한 컬럼에 적합합니다.</li>
</ul>
<h3 id="비트맵-인덱스">비트맵 인덱스</h3>
<ul>
<li>특징: 2차원 비트맵을 사용하여 각 행의 존재 여부를 비트로 표시합니다.</li>
<li>장점: 공간 효율성이 높고, 비트 연산을 통해 빠른 검색이 가능합니다.</li>
<li>사용 사례: 카디널리티가 낮고 중복되는 값이 많은 컬럼에 적합합니다.</li>
<li>예시: 성별, 상태, 부서 코드 등 도메인이 좁은 컬럼.</li>
</ul>
<p>성능 비교
B-트리의 시간 복잡도가 O(log N)인 반면, 비트맵 인덱스는 비트 연산을 통해 O(1)에 접근 가능합니다.
주의 사항: 데이터 변경이 빈번한 컬럼에는 적합하지 않습니다.</p>
<h2 id="sargable-쿼리와-non-sargable-쿼리">SARGable 쿼리와 Non-SARGable 쿼리</h2>
<p>💡 <strong>SARGable(Search ARGument able)</strong>은 데이터베이스가 인덱스를 활용하여 쿼리를 효율적으로 실행할 수 있는지 여부를 나타내는 용어입니다.</p>
<h3 id="sargable-쿼리">SARGable 쿼리</h3>
<p>인덱스를 활용하여 빠르게 데이터를 검색할 수 있는 쿼리.
특징: 인덱스가 존재하는 컬럼에 직접적인 비교나 범위 검색을 수행, 인덱스 시크(Index Seek)를 통해 효율적인 데이터 접근.</p>
<p>예시</p>
<pre><code class="language-sql">SELECT * FROM Users WHERE Age = 30;
SELECT * FROM Orders WHERE OrderDate BETWEEN &#39;2021-01-01&#39; AND &#39;2021-12-31&#39;;</code></pre>
<h3 id="non-sargable-쿼리">Non-SARGable 쿼리</h3>
<p>인덱스를 효과적으로 활용하지 못해 전체 테이블을 스캔해야 하는 쿼리.
특징: 컬럼에 함수나 연산이 적용되어 인덱스 사용이 불가능, 인덱스 스캔(Index Scan)이나 테이블 스캔(Table Scan)을 수행.</p>
<p>예시</p>
<pre><code class="language-sql">SELECT * FROM Users WHERE LEFT(Name, 1) = &#39;A&#39;;
SELECT * FROM Products WHERE Price * Quantity &gt; 1000;</code></pre>
<h2 id="최적화-팁">최적화 팁</h2>
<p>함수 사용 지양: WHERE 절에서 컬럼에 함수를 적용하지 말고, 가능하면 컬럼 자체를 조건으로 사용합니다.</p>
<ul>
<li>❌ 잘못된 예시: WHERE UPPER(Name) = &#39;JOHN&#39;;</li>
<li>✅ 올바른 예시: WHERE Name = &#39;John&#39;;</li>
</ul>
<p>인덱스 설계: 자주 조회되는 컬럼에 적절한 인덱스를 생성합니다.</p>
<p>와일드카드 사용 주의: LIKE 연산자 사용 시 와일드카드(%)를 문자열의 시작 부분에 사용하지 않습니다.</p>
<ul>
<li>❌ 잘못된 예시: LIKE &#39;%abc&#39; (인덱스 미사용)</li>
<li>✅ 올바른 예시: LIKE &#39;abc%&#39; (인덱스 사용 가능)</li>
</ul>
<p>조인 순서가 성능에 미치는 영향</p>
<p>쿼리 플랜의 성능은 테이블이 조인되는 순서에 크게 의존합니다.
예를 들어:
테이블 크기:</p>
<ul>
<li>A 테이블: 10행</li>
<li>B 테이블: 10,000행</li>
<li>C 테이블: 1,000,000행</li>
</ul>
<p>조인 순서 비교: B와 C를 먼저 조인: 대량의 데이터를 처리해야 하므로 시간이 오래 걸림.
A와 C를 먼저 조인: 작은 테이블과 큰 테이블을 먼저 조인하여 중간 결과셋의 크기를 줄일 수 있음.</p>
<p>결론: 작은 테이블을 우선적으로 조인하여 중간 결과셋의 크기를 최소화하는 것이 성능 향상에 유리합니다.</p>
<h2 id="결론">결론</h2>
<p>쿼리 최적화는 데이터베이스 성능을 향상시키기 위한 필수적인 과정입니다. 물리적 리소스의 효율적인 사용, 적절한 인덱스 설계, SARGable 쿼리 작성, 그리고 조인 순서의 최적화 등을 통해 쿼리의 실행 시간을 크게 단축할 수 있습니다. 이러한 원리와 기법을 이해하고 적용함으로써 더욱 효율적인 데이터베이스 운영이 가능해집니다. 🚀</p>
<h3 id="reference">reference</h3>
<p><a href="https://en.wikipedia.org/wiki/Query_optimization">https://en.wikipedia.org/wiki/Query_optimization</a>
<a href="https://www.youtube.com/watch?v=BHwzDmr6d7s">https://www.youtube.com/watch?v=BHwzDmr6d7s</a>
<a href="https://www.youtube.com/watch?v=TukZd6LjeBc">https://www.youtube.com/watch?v=TukZd6LjeBc</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[개발자 상반기 회고 feat. 실패 회고]]></title>
            <link>https://velog.io/@edwin_/%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%83%81%EB%B0%98%EA%B8%B0-%ED%9A%8C%EA%B3%A0-feat.-%EC%8B%A4%ED%8C%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@edwin_/%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%83%81%EB%B0%98%EA%B8%B0-%ED%9A%8C%EA%B3%A0-feat.-%EC%8B%A4%ED%8C%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Wed, 28 Aug 2024 12:47:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/edwin_/post/7e4870d5-dd4a-45e3-9234-9e11bdaa3a17/image.png" alt=""></p>
<p>2024 상방기에 여러 부트캠프, 회사에 지원을 했다.
현대 오토에버 채용 연계 국비지원은 cs테스트나 면접도 못 보고 서류탈락했고 싸피는 최종면접에서 떨어졌고, 네이버 부스트캠프는 장장 두달이 넘는 선발 프로세스(한달 동안의 챌린지를 마친 후 3차 코테 이후 멤버쉽 선발이 되지 못 했다)끝에 멤버쉽을 가지 못 하였다. 회사 정규직 또한 10개 정도 서류를 넣었지만 모두 서류탈락을 했다.</p>
<p>오늘은 이러한 실패 경험을 바탕으로 회고를 통해 부족한 점과 앞으로의 생각을 정리하고, 추후에 리마인드할 수 있도록 하려 한다. 또한 나와 같은 취준생이 있다면 내 회고를 보고 조금이라도 인사이트를 얻을 수 있지 않을까하는 바램이다.</p>
<p>내가 부족한 것은 알고 있었지만 회사 정규직 탈락은 그렇다해도 공부하기 위해 모집하는 부트캠프들도 탈락하니 더욱 난감했다. 그럼에도 이러한 과정에서 내가 깨달은 것들이 있었다.</p>
<h2 id="나의-단점">나의 단점</h2>
<p><strong>1. 문서화 역량</strong></p>
<p>문서화의 중요성은 네이버 부스트캠프를 진행하면서 깨닫게 되었다. 나는 학창시절에 공부를 잘하는 편은 아니었지만, 학습 후 별도의 학습 노트를 작성하는 타입도 아니었다. 오히려 잘 정리하는 친구의 노트를 빌려 공부했던 기역이 있다. 나의 노트를 적으려 할때 학습에 쏟아야할 집중력이 &quot;문서화 하는 행위&quot; 그자체에 분산되는 느낌이 너무 싫었다. 그래서 평소에 문서화를 하지 않았지만 그것은 한계가 분명했다.</p>
<p>나의 지식을 문서화하는 것은 단기적으로는 효과가 안보일 수 있지만 중장기적으로는 분명 쌓이는 수준이 다르다. 내가 작성한 문서는 더욱 쉽게 인덱싱할 수 있고 이것은 장기 기억력으로 더욱 쉽게 전환될 수 있음을 의미한다. 나아가 정리하면서 나의 추상적 지식을 구조화하여 구체화할 수 있고 또한 내가 무엇을 모르는지에 대해서 알 수 있다.</p>
<p>하지만 문서화 역량을 기르는 것은 단기간에 올리기 힘들단 것 또한 알게 되었다. 확실히 십년 넘게 지식을 문서화를 시켜본 사람과 그렇지 않은 사람의 역량 차이는 크며 문서화를 시도하는 행위 자체가 &quot;습관&quot;의 영역이기 때문에 문서화의 중요성을 알게 된다한들 그것을 잘 실천할 수 있는 것은 또 다른 영역이기 때문이다.</p>
<p><strong>2. 집중력 지구력</strong></p>
<p>최근 다른 사람과 짝을 지어 학습부터 설계, 구현까지 모든 프로세스를 함께 해본 경험이 있었고 나 혼자 공부할 때는 느낄 수 없었지만 다른 사람과 함께 할때는 상대적으로 나의 집중력이 떨어지고 있는지 쉽게 확인할 수 있었다.</p>
<p>이전까지만 하더라도 적절한 휴식이 필요하다는 것을 흘려들었고 개인적으로 집중력이 좋은 편인줄 알고 있었다. 짝 프로그래밍을 경험 한 이후 집중력 지구력이 안좋다는 것을 깨닫고 나아가 앞서 휴식의 중요성을 주장하던 글과 말들을 다시 한번 깊게 생각할 수 있었다. 오랫동안 코딩을 할 때 의도적으로 휴식을 가져간적이 없었지만 이젠 그것의 중요성을 알고 나의 집중력을 항시 트래킹하려는 시도를 하고 있다. 그 중 하나의 방법으로 정해진 시간을 만들어 집중하고 휴식하는 루틴을 만드는 것도 좋은 방법인 것 같다.</p>
<p><strong>3. 경험</strong></p>
<p>프로젝트 경험이 현저히 부족하다. 팀 프로젝트를 했던 경험이 있지만 나의 기여도는 많이 낮아서 처음부터 시작하는 개인 프로젝트 경험의 필요성을 절실히 느끼고 있다. 그래서 최근에 개인 또는 팀 프로젝트를 위한 주제를 하나 정했다. 이 주제로 기획과 설계부터 배포, 트래픽 경험, 나아가 고도화까지 일련의 과정을 깊게 경험해보고 싶었다. 이러한 생각을 통해서 다음 우선순위는 프로젝트로 정해졌다.</p>
<h2 id="나의-장점">나의 장점</h2>
<ol>
<li><p>좋은 질문을 하는 것
여러 팀 프로젝트에서 받은 공통적인 긍정적 피드백이 있었다. 충분히 생각할 가치가 있고 생각지도 못한 좋은 질문들을 자주 던져 같이 있으면 배워가는게 많다는 피드백이다. 네이버 부스트캠프 챌린지 과정을 진행하면서 정말 많은 팀들을 만났는데 모두 이와 비슷한 피드백이 있었다는 점에서 나의 특별한 구체적인 장점을 찾아서 좋았다. 특히 AI를 잘 활용하면 이러한 장점이 시너지를 발휘할 수 있다고 생각된다. 이러한 장점을 잘 갈고 닦아서 극대화시켜 나만의 차별점을 만들고 싶다.</p>
</li>
<li><p>팀 분위기 리드를 통한 팀워크 향상
나는 대부분 낯을 가리지 않기 때문에 팀 초반에 내가 리드를 하는 상황이 많았다. 이후에도 자연스럽게 팀을 리딩하는 역할을 맡아 팀원들의 의견을 조율하고 좋은 주제의 토론을 만드는 나의 모습을 찾을 수 있었다. 나는 거의 항상 팔로워의 역할만 했는데 리더의 면모도 가지고 있음을 이번에 알게 되었다.</p>
</li>
</ol>
<h2 id="내가-좋아하는-일">내가 좋아하는 일</h2>
<ol>
<li><p>사람과 함께하는 일
계속해서 낯선 사람들을 만나는 일이 나는 정말 재미있다는 것을 알게 되었다. 네부캠에서 일주일에 두번씩 팀을 만들어서 팀 활동을 하는 상황들이 있었는데 새로운 팀은 어떨까 하고 새 팀이 나오는 날이 설레고 기대가 되었다. 그러고 낯선 사람들과 인사하는 것부터 새로운 사람과 짝 코딩을 하는 것까지 혼자 공부, 코딩하는 것 보다 더욱 재미있게 했다. 반대로 오랫동안 주변에 같은 사람들만 있으면 즉, 한동안 새로운 변화가 없으면 쉽게 지루해지는 것 같다. 분명 낯선 사람들을 만나는 일에 큰 스트레스를 받는 사람들도 있을텐데 내가 이러한 성격을 지닌 업무 환경에 적합하다는 것을 알게 되었다. 분명 이러한 성격에 맞는 개발 관력 직무, 직군이 있을 것이다.</p>
</li>
<li><p>기획
구현을 하는 시간도 물론 좋았지만 추상적인 컨셉에 대해서 서로 이야기하고 토론하고 구체화시키는 과정이 나는 더 재미있게 참여했던 것 같다. 그래서 이번 기회에 기획자에 대해서도 한번 생각을 해보게 된 계기가 되었다. 하지만 내가 생각하는 좋은 기획자자의 필요조건은 충분한 프로젝트 기획 경험이라고 생각되어서 신입으로 기획자를 알아보지는 않을 것 같고 이후에 중간 경력 개발자가 되면 충분히 기획자로 일할 생각을 해보았다.</p>
</li>
<li><p>예측할 수 없는 환경
1번과 어느정도 같은 내용이다. 오히려 3번이 1번에 대한 이유가 될 수 있을 것 같다. 최근에 이러한 환경에 스트레스를 느끼는 사람이 생각보다 많음을 알게되었다. 예측할 수 없는, 안정적이지 않은 환경에 관심이 가는 성격을 통해서 나의 도메인도 정할 수 있겠다는 생각이 들었다. 예를 들어 제조업에서 스마트팩토리 직군에서는 해외공장 파견을 매우 자주 나가기 때문에 해당 팀 사람들이 스트레스를 받는 다는 이야기를 들었는데 이러한 나의 성격은 분명 이러한 직군에서 큰 스트레스를 받지 않고 오히려 즐겁게 일할 수 있겠다고 생각을 했다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[TCP 통신을 알아보자]]></title>
            <link>https://velog.io/@edwin_/JS-Server%EC%99%80-client-tcp-%ED%86%B5%EC%8B%A0-%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@edwin_/JS-Server%EC%99%80-client-tcp-%ED%86%B5%EC%8B%A0-%ED%95%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Wed, 07 Aug 2024 01:40:17 GMT</pubDate>
            <description><![CDATA[<h1 id="tcptransmission-control-protocol">TCP(Transmission Control Protocol)</h1>
<p>TCP는 OSI 7계층의 4계층 (Transport) 레벨이며 때로는 3 계층 즉, Network의 IP 프로토콜과 함께 사용되기 때문에 &quot;TCP/IP&quot;라고도 불립니다.
<img src="https://velog.velcdn.com/images/edwin_/post/fd106a60-abff-4aa3-9f1e-5832fd7e2bea/image.png" alt=""></p>
<p>UDP와 다르게 안전한 데이터 통신을 보장하는 프로토콜입니다. TCP의 연결 과정을 살펴보면 왜 안전한 통신인지 확인 할 수 있습니다.</p>
<h3 id="three-way-handshake">Three way handshake</h3>
<ol>
<li><p>클라이언트는 서버에게 연결 요청의 SYN이라는 비트를 1을 만들어 TCP 헤더 정보를 설정하고 패킷을 생성하여 보낸다.</p>
</li>
<li><p>서버는 받은 패킷을 기반으로 수신처 포트 번호에 해당하는 소켓을 찾고 거기에 해당 클라이언트에 대한 정보를 저장한다.</p>
</li>
<li><p>서버는 마찬가지로 SYN 비트를 만들고 정상적으로 처리했다는 걸 알리기 위해 ACK 비트를 1로 해서 클라이언트에게 패킷을 보냅니다.</p>
</li>
<li><p>클라이언트는 받은 패킷 정보를 기반으로 서버 측의 접속 동작이 성공했는지 확인합니다.</p>
</li>
<li><p>클라이언트는 서버가 정상적으로 처리됐다는 것을 인지하고 자신도 패킷을 제대로 받았다는 것을 알리기 위해 ACK 비트를 1로 만들고 패킷을 만들어 서버에게 전송을 합니다.
이로써 소켓은 데이터를 송수신할 수 있는 상태가 됩니다.</p>
</li>
</ol>
<p>이러한 일련의 초기 연결 과정을 Three way handshake라고 불리웁니다. SYN 1을 보내고 SYN와 ACK를 보내고 마지막으로 ACK를 보내기 때문입니다. 다음은 three way handshake를 도식화한 이미지입니다.</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/a13c846d-eb95-48ad-b6ef-1e52df4f9e2b/image.png" alt=""></p>
<h3 id="tcp-세그먼트">TCP 세그먼트</h3>
<p>TCP 세그먼트는 헤더와 데이터 필드로 나눠집니다.</p>
<p>헤더에는 다음과 같은 요소들이 있습니다.</p>
<ul>
<li>Source Port: 데이터를 발송하는 애플리케이션의 포트 번호입니다.</li>
<li>Destination Port: 데이터를 수신하는 애플리케이션의 포트 번호입니다.</li>
<li>Sequence Number(SYN): TCP 통신 과정에서 데이터를 일정 단위로 분할하는데요. 분할된 데이터의 순서입니다.</li>
<li>Acknowledgment Number(ACK): 데이터를 수신하는 애플리케이션 입장에서, 다음으로 받고 싶은 TCP 세그먼트의 Sequence Number입니다.</li>
</ul>
<p>TCP가 데이터를 순서대로 도착하는 것은 아닙니다. 네트워크 계층에서 RIP(Routing Information Protocol)과 같은 데이터 패킷 전달 프로토콜을 통해서 각 패킷들을 다른 경로로 유동적으로 나눠서 보낼 수 있기 때문입니다. 따라서 도착 순서는 정렬 상태를 보장할 수는 없지만 UDP와는 다르게 헤더에 포함된 SYN로 정렬시킬 수 있습니다.</p>
<p>ACK를 통해서 UDP와 다르게 상대방이 해당 패킷을 받았다는 것을 알 수 있기 때문에 안전한 통신이라고 합니다.</p>
<pre><code class="language-text">0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |       |C|E|U|A|P|R|S|F|                               |
   | Offset| Rsrvd |W|C|R|C|S|S|Y|I|            Window             |
   |       |       |R|E|G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           [Options]                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               :
   :                             Data                              :
   :                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</code></pre>
<p><br><br><br></p>
<h3 id="참고">참고</h3>
<p><a href="https://datatracker.ietf.org/doc/html/rfc9293">https://datatracker.ietf.org/doc/html/rfc9293</a></p>
<p><a href="https://docs.tosspayments.com/resources/glossary/tcp">https://docs.tosspayments.com/resources/glossary/tcp</a></p>
<p><a href="https://valueelectronic.tistory.com/102">https://valueelectronic.tistory.com/102</a></p>
<p><a href="https://www.cloudflare.com/ko-kr/learning/ddos/glossary/tcp-ip/">https://www.cloudflare.com/ko-kr/learning/ddos/glossary/tcp-ip/</a></p>
<p><a href="https://s3-ap-northeast-1.amazonaws.com/exemdocuments/intermax/wh-apm_TCP.pdf">https://s3-ap-northeast-1.amazonaws.com/exemdocuments/intermax/wh-apm_TCP.pdf</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[linux 파일 시스템]]></title>
            <link>https://velog.io/@edwin_/linux-%ED%8C%8C%EC%9D%BC-%EC%8B%9C%EC%8A%A4%ED%85%9C</link>
            <guid>https://velog.io/@edwin_/linux-%ED%8C%8C%EC%9D%BC-%EC%8B%9C%EC%8A%A4%ED%85%9C</guid>
            <pubDate>Mon, 05 Aug 2024 02:14:04 GMT</pubDate>
            <description><![CDATA[<h1 id="📁-file-and-file-system">📁 File and File System</h1>
<h2 id="개요">개요</h2>
<p>파일은 데이터를 저장하고 관리하는 기본 단위입니다. 이는 컴퓨터 시스템에서 중요한 역할을 하며, 파일 시스템은 이러한 파일들을 체계적으로 관리하는 시스템입니다. 이 문서에서는 파일과 파일 시스템의 개념, 디렉토리 엔트리, 링크, 권한, 마운트, 파일 할당, 그리고 EXT 파일 시스템에 대해 자세히 설명합니다.</p>
<h2 id="파일file-🗃️">파일(File) 🗃️</h2>
<p>파일은 데이터를 담는 그릇입니다. 이는 연속적인 데이터를 유의미한 구분으로 나누기 위해 존재하며, 텍스트 파일, 이미지 파일, 비디오 파일 등 다양한 형태로 존재할 수 있습니다. 각 파일은 이름, 크기, 수정 날짜 등 여러 메타데이터를 포함합니다.</p>
<h2 id="파일-시스템file-system-🗄️">파일 시스템(File System) 🗄️</h2>
<p>파일 시스템은 파일을 저장하고 관리하는 시스템입니다. 이는 파일의 메타데이터(이름, 확장자, 권한 등)를 이용해 파일을 관리하며, 이러한 메타데이터는 디렉토리에 저장됩니다. 디렉토리는 파일과 파일의 메타데이터를 담고 있는 파일로서, 트리 구조로 구성됩니다. 🌳</p>
<h2 id="디렉토리-엔트리directory-entry-📑">디렉토리 엔트리(Directory Entry) 📑</h2>
<p>디렉토리 엔트리는 디렉토리를 표현하는 자료구조입니다. 각 디렉토리 엔트리는 파일의 이름과 inode를 가리키는 포인터로 구성됩니다. inode는 파일 이름을 제외한 파일 메타데이터를 포함하며, 파일의 실제 데이터를 가리킵니다.</p>
<ul>
<li><strong>Directory Entry = 파일 이름 + inode를 가리키는 포인터</strong></li>
<li><strong>inode</strong>는 파일의 크기, 소유자, 권한, 데이터 블록 위치 등의 정보를 포함합니다.</li>
</ul>
<h2 id="링크link-🔗">링크(Link) 🔗</h2>
<p>링크는 파일 시스템에서 파일이나 디렉토리에 대한 참조를 만드는 방법입니다. 링크에는 소프트 링크(심볼릭 링크)와 하드 링크 두 가지가 있습니다.</p>
<h3 id="소프트-링크심볼릭-링크-🧷">소프트 링크(심볼릭 링크) 🧷</h3>
<p>소프트 링크는 파일의 포인터(경로)만 링크합니다. 이는 파일의 경로를 참조하며, 원본 파일이 삭제되면 소프트 링크는 깨집니다. 소프트 링크는 디렉토리를 링크할 수 있습니다.</p>
<h3 id="하드-링크-🔩">하드 링크 🔩</h3>
<p>하드 링크는 파일의 원본 내용을 다른 이름(경로)로 만듭니다. 이는 파일의 inode 번호를 공유하므로 원본 파일이 삭제되더라도 하드 링크는 계속 존재합니다. 하드 링크는 디렉토리를 링크할 수 없습니다.</p>
<h2 id="링크와-트리-구조-🔍">링크와 트리 구조 🔍</h2>
<p>디렉토리는 트리 구조로 구성됩니다. 링크를 사용하면 서로 다른 말단 노드에서 파일을 참조할 수 있지만, 트리 구조는 깨지지 않습니다. 소프트 링크는 파일의 경로를 참조하기 때문에 트리 구조를 변경하지 않습니다. 하드 링크는 디렉토리를 링크할 수 없으므로 순환 참조 문제를 방지합니다.</p>
<h2 id="권한permission-🛡️">권한(Permission) 🛡️</h2>
<p>파일 시스템에서 파일과 디렉토리의 접근 권한은 중요합니다. 각 파일과 디렉토리는 소유자(user), 그룹(group), 그리고 기타 사용자(others)에게 서로 다른 권한을 설정할 수 있습니다.</p>
<ul>
<li><strong>user</strong>: 파일의 소유자</li>
<li><strong>group</strong>: 소유자가 속한 그룹</li>
<li><strong>others</strong>: 소유자가 속한 그룹에 속하지 않은 사용자</li>
</ul>
<p>권한은 <code>r</code>(읽기), <code>w</code>(쓰기), <code>x</code>(실행)로 나타내며, <code>chmod</code> 명령어를 통해 수정할 수 있습니다.</p>
<pre><code class="language-sh">chmod u+rwx,g+rx,o+r file.txt</code></pre>
<p>위 명령어는 파일 소유자에게 읽기, 쓰기, 실행 권한을, 그룹 사용자에게 읽기, 실행 권한을, 기타 사용자에게 읽기 권한을 부여합니다.</p>
<h2 id="마운트mount-💾">마운트(Mount) 💾</h2>
<p>마운트는 HDD, USB 등의 2차 저장장치를 로컬 파일 시스템에 연결하는 과정입니다. 각각의 장치는 자체 루트를 가진 파일 시스템이지만, 마운트를 통해 하나의 파일 시스템 안에 있는 것처럼 관리할 수 있습니다. 예를 들어, 외장 하드를 /mnt/external 디렉토리에 마운트할 수 있습니다.</p>
<pre><code class="language-sh">mount /dev/sdb1 /mnt/external</code></pre>
<p>위 명령어는 /dev/sdb1 장치를 /mnt/external 디렉토리에 마운트합니다.</p>
<h2 id="파일-할당file-allocation-🗂️">파일 할당(File Allocation) 🗂️</h2>
<p>디스크에 파일을 저장하기 위해 공간을 관리하는 방법에는 연속 할당, 연결 할당, 색인 할당 등이 있습니다. 리눅스에서는 주로 색인 할당 방식을 사용합니다.</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/a796f4eb-2e36-4887-bbb4-d1537622f894/image.jpg" alt=""></p>
<ul>
<li><p>연속 할당(Contiguous Allocation)
연속 할당은 파일의 모든 블록이 디스크 상에서 연속된 위치에 저장되는 방식입니다. 이는 빠른 접근 속도를 제공하지만, 파일 크기가 변경될 때 조각화(fragmentation)가 발생할 수 있습니다.</p>
</li>
<li><p>연결 할당(Linked Allocation)
연결 할당은 파일의 각 블록이 다음 블록을 가리키는 포인터를 포함하는 방식입니다. 이는 파일 크기 변경에 유연하지만, 블록을 순차적으로 읽어야 하기 때문에 접근 속도가 느릴 수 있습니다.</p>
</li>
<li><p>색인 할당(Index Allocation)
색인 할당은 파일의 모든 블록 주소를 색인 블록에 저장하는 방식입니다. 이는 연속 할당의 조각화 문제와 연결 할당의 느린 접근 속도를 해결할 수 있습니다.</p>
</li>
</ul>
<h2 id="ext-파일-시스템-🛠️">EXT 파일 시스템 🛠️</h2>
<p>EXT3와 EXT4 파일 시스템은 저널링 기능을 제공합니다.</p>
<h3 id="저널링journaling-📝">저널링(Journaling) 📝</h3>
<p>저널링은 파일 시스템의 메타데이터를 기록하여 시스템 충돌이나 비정상적인 종료 후 데이터를 복구할 수 있게 합니다. 저널링은 데이터를 캐시에 넣은 뒤, 원본과 캐시의 상태가 달라질 수 있기 때문에 업데이트 상태를 관리합니다.</p>
<h3 id="ext4의-특징-🌟">EXT4의 특징 🌟</h3>
<p>EXT4는 EXT3보다 향상된 기능을 제공합니다. 이는 더 큰 파일과 볼륨을 지원하며, 효율적인 공간 할당과 빠른 파일 시스템 검사를 제공합니다.</p>
<h3 id="참고">참고</h3>
<p><a href="https://www.youtube.com/watch?v=oeuVjeeoLSQ">https://www.youtube.com/watch?v=oeuVjeeoLSQ</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네이버부스트캠프 3주차 KPT 회고]]></title>
            <link>https://velog.io/@edwin_/%EB%84%A4%EC%9D%B4%EB%B2%84%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-3%EC%A3%BC%EC%B0%A8-KPT-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@edwin_/%EB%84%A4%EC%9D%B4%EB%B2%84%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-3%EC%A3%BC%EC%B0%A8-KPT-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sat, 03 Aug 2024 10:02:05 GMT</pubDate>
            <description><![CDATA[<h3 id="주차-느낀-점">주차 느낀 점</h3>
<p>3주차에서는 나에 대해서 객관적으로 알게된 점이 많았다. 짝 구현을 진행하면서 짝과 함께 학습도 하고 설계, 구현까지 모두 진행하는데 짝을 관찰하면서 나와는 어떻게 다른지 생각해볼 수 있었다. 크게 2가지 정도를 알게 되었다.</p>
<ol>
<li><p>나는 성격이 급했는지 충분한 학습을 하지 않고 설계, 구현에 들어간다.
나는 충분하다고 생각했지만 사실은 설계, 구현에 필요한 학습을 하지 않고 들어갔다. 짝과 함께 설계를 하기 때문에 나의 생각을 다시 한번 말로 정리하면서 상대방을 납득시켜야한다. 그 과정에서 나는 내가 충분한 학습을 진행하지 않았음을 알게 되었다. 나의 주장에는 근거가 빈약했고 말을 하면서 나도 내 주장에 의문을 가지는 일이 많았다. -&gt; 그래서 이번에는 과할정도라고 판단될 만큼 충분히 학습을 진행하고 설계와 구현을 해봤다. 시작 시간은 많이 늦었지만 결과론적으로 비슷한 시간에 끝났다.. </p>
</li>
<li><p>나는 집중력의 기복이 심했다. 짝은 15시간의 시간을 일관된 집중력으로 집중했지만 나는 중간중간 코드가 머리에 들어오지 않음을 느낄 수 있었다. 잠시 휴식을 갖고 다시 진행하면 그나마 돌아왔다. 나는 집중력이 &quot;깡&quot;이라고 생각하고 엉덩이로 버티는 것이라고 잘못 생각하였다. 다른 사람들이 산책하거나 잠시 휴식을 해야한다는 말을 흘려들었다.. 이번 주에 그것이 실제로 의미있는 효과가 있고 나의 집중력에도 명확한 한계가 있음을 깨닫게 되었다. 앞으로 나의 집중력의 한계가 어디인지 확실히 알고 그 집중력의 한계가 오기 전 적절한 나만의 휴식 법을 찾아서 지속적인 집중력 컨트롤이 필요하다는 것을 몸소 느꼈다.</p>
</li>
</ol>
<h2 id="☀️-keep">☀️ Keep</h2>
<ol>
<li><p>남이 아닌 자신과의 비교 -&gt; 처음에는 남의 속도가 신경쓰였던 기억이 있다. 하지만 이제 남의 속도를 보는 것이 아니고 내가 어제보다 얼마나 성장했는지를 보게 되었다. </p>
</li>
<li><p>긍정적인 마인드 -&gt; 미션에 대한 과도한 집착은 벗어난 것 같다. 구현에 집중하기 보다도 학습 그자체에 집중하는 것이 더 남는게 많을 것 같다.</p>
</li>
</ol>
<h2 id="🆘-problem">🆘 Problem</h2>
<ol>
<li><p>아침에 일어나는게 더 힘들어졌다.. -&gt; 아직도 늦게 자는 습관을 버리지 못 했다.. 하지만 이 문제는 해결법이 잘 떠오르지 않는다... 욕심이 많아서 조금만 더 하면 완벽해 질 것 같은데... 라는 생각 때문에 잠을 거르고 계속 집중하게 된다.. 아마 확실한 기준이 없어서 그런것 같다. 기준으 한번 생각해보자</p>
</li>
<li><p>학습 정리를 당일에 완성하지 못 했다 -&gt; 새벽에 학습 정리를 쓰는게 아니라 낮에 틈틈히 작성하려고 노력해야겠다.</p>
</li>
</ol>
<h2 id="🔫-try">🔫 Try</h2>
<ol>
<li><p>새벽에 끝내는 시간에 대한 확실한 기준 정하기 -&gt; 완성을 하지 못 했더라도 내일 컨디션을 위해서는 이러한 기준이 필요할 것이다. 최소 6시간 수면을 지켜보자</p>
</li>
<li><p>앞서 집중력에 대해서도 말했다. 중간 중간 휴식을 의도적으로 가져가고 그 휴식시간에 휴식하면서 학습 정리를 하는 것도 괜찮을 것 같단 생각이 들었다. 중간 중간 학습 정리를 하면서 지금 내가 가는 방향이 맞는지 다시 검증 할 수도 있을 것 같다. 잠시 멈추고 숲을 보는 연습을 해보자</p>
</li>
</ol>
<p><a href="https://velog.io/@edwin_/%EB%84%A4%EC%9D%B4%EB%B2%84%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-1%EC%A3%BC%EC%B0%A8-KPT-%ED%9A%8C%EA%B3%A0">네이버부스트캠프 1주차 KPT 회고</a></p>
<p><a href="https://velog.io/@edwin_/%EB%84%A4%EC%9D%B4%EB%B2%84%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-2%EC%A3%BC%EC%B0%A8-KPT-%ED%9A%8C%EA%B3%A0">네이버부스트캠프 2주차 KPT 회고</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[git 내부 동작 원리]]></title>
            <link>https://velog.io/@edwin_/git-%EB%82%B4%EB%B6%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@edwin_/git-%EB%82%B4%EB%B6%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Wed, 31 Jul 2024 01:15:20 GMT</pubDate>
            <description><![CDATA[<h2 id="🌍-깃은-하나의-분산-버전-관리-시스템">🌍 깃은 하나의 분산 버전 관리 시스템</h2>
<p>분산 버전 관리 시스템(Distributed Version Control System, DVCS)은 소스 코드와 히스토리를 중앙 서버뿐만 아니라 사용자의 로컬 저장소에서도 완전한 복사본으로 저장하는 방식입니다. 이점은 로컬에도 복사본이 있기 때문에 중앙 서버의 의존도를 줄일 수 있고, 개발자들이 로컬에서 독립적으로 작업하고 변경 사항을 저장할 수 있다는 것입니다.</p>
<p>DVCS의 예시는 Git, Mercurial, Bazzar, Fossil과 같은 예시가 있지만 이 중 git에 대해서 알아보겠습니다.</p>
<h2 id="📂-git은-어떻게-소스-코드를-저장하나">📂 Git은 어떻게 소스 코드를 저장하나?</h2>
<p>Git은 모든 데이터를 파일 형태로 저장합니다. Git의 개발자인 리누스 토르발스는 리눅스의 개발자이기도 합니다. 리눅스와 Git은 모두 파일 시스템의 특성을 활용합니다. 둘 다 트리 구조와 계층적 관리를 합니다. Git은 다음과 같이 Git objects를 만들어 계층적으로 관리를 합니다.</p>
<h3 id="🗂️-git-objects">🗂️ Git Objects</h3>
<ul>
<li><p><strong>blob</strong>: 파일의 콘텐츠를 저장하는데 사용합니다. 파일의 메타 데이터는 없으며 오직 파일의 내용만 압축하여 저장하고 해당 압축 파일을 SHA-1 해시화 하여 이름으로 지정합니다.</p>
</li>
<li><p><strong>tree</strong>: 디렉토리 구조를 나타내는 객체입니다. tree는 blob과 다른 tree에 대한 포인터를 포함하여 디렉토리 내의 파일과 하위 디렉토리를 나타냅니다.</p>
</li>
<li><p><strong>commit</strong>: root tree에 대한 포인터, 부모 commit에 대한 포인터, 작성자, commit message 등을 포함합니다.</p>
</li>
<li><p><strong>tag</strong>: 특정 commit에 대한 참조를 추가적인 메타데이터와 함께 저장하는 객체입니다. 주석 태그와 경량 태그로 나뉘며 주석 태그는 태그 이름, 설명, 태그를 만든 사람 등이 포함되며 경량 태그는 특정 커밋을 가리키는 포인터입니다.</p>
</li>
</ul>
<h2 id="🛠️-git-폴더-구조">🛠️ .git 폴더 구조</h2>
<p>먼저 <code>init</code> 명령어를 통해 <code>.git</code> 폴더가 만들어지며 하위에 여러 폴더와 파일이 생기는데 이 중 <code>objects</code> 폴더에 앞서 말했던 객체들이 들어가게 됩니다.</p>
<h2 id="➕-add-명령어">➕ add 명령어</h2>
<p><code>add</code> 명령어를 실행하면 <code>add</code>한 파일에 대해서 내용을 압축을 하여 SHA-1 해시화합니다. 나온 해시값의 두 글자는 폴더 이름, 나머지는 파일 이름으로 <code>objects</code> 폴더 밑에 저장합니다. 그리고 <code>index</code> 파일 안에 해당 파일에 대한 파일모드(종류, 권한)와 해시값, 파일 이름이 저장됩니다.</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/25bd1cf4-21dd-436d-8cc5-98c582a07b41/image.png" alt=""></p>
<h2 id="📝-commit-명령어">📝 commit 명령어</h2>
<p>이후 <code>commit</code> 명령어가 들어오면 <code>index</code> 파일을 참고해서 tree 객체를 만들게 됩니다. tree 객체는 <code>index</code> 파일과 비슷하게 파일 모드, 해시값, 파일 이름에 대한 정보를 개행 단위로 저장합니다. 만일 폴더의 깊이가 2개 이상이라면 폴더 레벨당 하나씩 tree를 만들게 됩니다. 그 뜻은 tree 안에 tree 포인터가 들어가게 됩니다. 그리고 커밋 객체를 만들게 되는데, root tree와 부모 커밋과 작성자, 커밋 메시지를 넣어서 저장하게 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/37d1e7b6-2e4a-4e8f-9819-67a5005cae3b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/21991f3c-84da-49dd-9b99-2e0c5154d8f7/image.png" alt=""></p>
<h2 id="🔄-같은-내용의-다른-파일-이름을-add할-경우">🔄 같은 내용의 다른 파일 이름을 add할 경우</h2>
<p>앞선 <code>add</code> 프로세스에서 파일 내용을 압축하여 해시 값을 뽑는데, 같은 파일의 내용일 경우 파일 이름이 달라도 같은 해시 값을 가지기 때문에 <code>index</code> 파일에 기록할 때 같은 포인터를 가리키게 됩니다.</p>
<h2 id="참고">참고</h2>
<p><a href="https://opentutorials.org/course/2708/15240">https://opentutorials.org/course/2708/15240</a>!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] Event Emitter를 사용해보자]]></title>
            <link>https://velog.io/@edwin_/Event-Emitter</link>
            <guid>https://velog.io/@edwin_/Event-Emitter</guid>
            <pubDate>Mon, 29 Jul 2024 02:16:21 GMT</pubDate>
            <description><![CDATA[<h1 id="🚀-eventemitter란">🚀 EventEmitter란?</h1>
<p><code>EventEmitter</code>은 Node.js에서 제공하는 클래스 중 이벤트 기반 프로그래밍을 지원하는 클래스입니다. 이를 통해 객체들이 서로 이벤트를 주고받아 비동기적으로 소통할 수 있습니다.</p>
<p>기본 구조는 <strong>pub/sub 패턴</strong> 기반으로 움직입니다. Pub/Sub 패턴에 대해 더 알고 싶다면 제가 쓴 <a href="https://velog.io/@edwin_/pub-sub-%ED%8C%A8%ED%84%B4">블로그 글</a>을 참고해주세요. 📝</p>
<p><code>EventEmitter</code>을 사용하려면 발행하는 로직과 구독하는 로직이 필요합니다.</p>
<ul>
<li><p><strong>발행(Publish)</strong>: <code>emit</code> 메서드를 이용해 이벤트를 발행하며, 동시에 데이터도 함께 전달할 수 있습니다. 발행된 이벤트는 해당 이벤트를 구독한 모든 리스너에게 전달됩니다.</p>
</li>
<li><p><strong>구독(Subscribe)</strong>: <code>on</code> 메서드를 이용해 이벤트를 구독할 수 있습니다. 구독할 때 첫 번째 매개변수로 이벤트 이름을, 두 번째 매개변수로는 콜백 함수를 전달합니다. 해당 이벤트가 발생하면 이 콜백 함수가 호출됩니다.</p>
</li>
</ul>
<h2 id="예제-코드-🧑💻">예제 코드 🧑‍💻</h2>
<p>아래는 <code>EventEmitter</code>를 사용하는 간단한 예시입니다.</p>
<pre><code class="language-javascript">const EventEmitter = require(&#39;events&#39;);

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();

// &#39;event&#39;라는 이벤트를 구독
myEmitter.on(&#39;event&#39;, () =&gt; {
  console.log(&#39;An event occurred!&#39;);
});

// &#39;event&#39;라는 이벤트를 발행
myEmitter.emit(&#39;event&#39;);</code></pre>
<p>위 코드에서 myEmitter.on(&#39;event&#39;, ...)는 event라는 이름의 이벤트를 구독합니다. 이 이벤트가 발행될 때마다 구독된 리스너가 호출됩니다.</p>
<h2 id="eventemitter의-주요-메서드-🛠">EventEmitter의 주요 메서드 🛠</h2>
<p>•    emit(eventName, ...args): 발행자가 호출하여 특정 이벤트를 발생시킵니다. eventName은 이벤트의 이름이고, ...args는 이벤트 리스너에게 전달될 인수들입니다.</p>
<p>•    on(eventName, listener): 구독자가 특정 이벤트를 구독하도록 등록합니다. 이벤트가 발생하면 listener 함수가 호출됩니다.</p>
<p>•    once(eventName, listener): 한 번만 호출될 이벤트 리스너를 등록합니다. 이벤트가 발생하면 리스너가 호출되고 자동으로 제거됩니다.</p>
<p>•    removeListener(eventName, listener): 특정 이벤트에 대한 리스너를 제거합니다.</p>
<p>•    removeAllListeners(eventName): 특정 이벤트나 모든 이벤트에 대한 리스너를 모두 제거합니다.</p>
<h2 id="pubsub-패턴의-장점-🌟">Pub/Sub 패턴의 장점 🌟</h2>
<ol>
<li><p>느슨한 결합: 발행자와 구독자는 서로에 대해 알 필요가 없으며, 직접 참조하지 않습니다. 이는 시스템의 모듈화와 유지보수를 용이하게 합니다.</p>
</li>
<li><p>확장성: 새로운 이벤트나 구독자를 추가해도 기존 시스템에 영향을 주지 않으므로, 확장이 쉽습니다.</p>
</li>
<li><p>비동기 처리: 이벤트 기반의 비동기 처리 모델을 쉽게 구현할 수 있어, 시스템 성능을 향상시킬 수 있습니다.</p>
</li>
</ol>
<p>EventEmitter는 이러한 Pub/Sub 패턴을 통해 효율적인 이벤트 관리와 비동기 처리를 가능하게 하며, Node.js 애플리케이션에서 핵심적인 역할을 합니다. 🎯</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네이버부스트캠프 2주차 KPT 회고
]]></title>
            <link>https://velog.io/@edwin_/%EB%84%A4%EC%9D%B4%EB%B2%84%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-2%EC%A3%BC%EC%B0%A8-KPT-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@edwin_/%EB%84%A4%EC%9D%B4%EB%B2%84%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-2%EC%A3%BC%EC%B0%A8-KPT-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 28 Jul 2024 19:12:00 GMT</pubDate>
            <description><![CDATA[<h3 id="주차-느낀-점">주차 느낀 점</h3>
<p>1주차 회고에서는 문서화의 중요성을 깨달은 것이 메인 주제였다.
2주차에서 깨달은 것은 문서화 역량은 짧은 시간에 올리기가 생각보다 어렵다는 것이다. 문서화를 미루지 않겠다고 다짐했지만 그때그때 정리하는게 오래 가지 않았다... 역시 습관이라는게 무서운 것이라는 생각이 들었다.</p>
<p>가장 중요한 것은 &quot;미루지 않는 것&quot;이라는 것을 깨달았다. 문서화를 잘하는 팀원을 유심히 관찰했었다. 팀원에게 &quot;주말에 몰아서 문서화를 하는데 너무 힘들다&quot;고 푸념했던 기억이 있다. 팀원은 이렇게 말했다. &quot;저도 주말에 미루면 그냥 하나도 안하고 포기할 것 같아요...ㅎ&quot;
앞선 경험은 문서화를 잘하는 사람은 미루지 않는 습관을 가진 사람이구나 하고 생각하게 되었다.</p>
<p>&quot;미루지 않는 것, 꾸준히 하는 것&quot; 제일 쉬워보일 수 있지만 제일 어려운 일이다. 노력하려고 했지만 문서화를 미루는 내가 너무 싫고 허탈했다. 하지만 문서화는 습관이고 단기적으로 확 좋아질 수 없는 역량인 것을 알고 난 후 나 자신을 좀더 장기적으로 응원하고 노력하는 시간이 필요한 것 같다.</p>
<h2 id="☀️-keep">☀️ Keep</h2>
<ol>
<li><p>매일 7시 반에 일어나기 -&gt; 새벽까지 과제를 한다고 너무 피곤해서 힘들지만 10시부터 스케쥴을 해내기 위해서는 어쩔 수 없이 지켜야하는 나의 루틴이다. 그럼에도 잘 하고 있음으로 나에게 칭찬을 해주자:)</p>
</li>
<li><p>열정을 가지고 노력 -&gt; 잠을 줄이는 것이 좋다는 뜻이 아니지만 잘을 줄이고 구현을 했다는 뜻은 그 만큼 열정을 가지고 노력했다고 해석할 수 있다.</p>
</li>
</ol>
<p>고3 때도 이렇게 노력하지 않았다.. 대중교통에서 휴대폰도 안보는 사람인데 노트북을 꺼내서 코딩을 했다.. &quot;나도 이렇게 집중하고 노력할 수 있구나&quot; 느꼈다. 나의 또 다른 모습을 볼 수 있어서 좋았다.</p>
<h2 id="🆘-problem">🆘 Problem</h2>
<ol>
<li><p>해설 영상을 미뤄 몰아서 봤다. -&gt; 구현에 집중 하느라 해설 영상이 공개가 될 시점에 확인을 못 하는 경우가 많았다. 또 구현을 다한 시점에는 새벽이여서 피곤해서 쉽게 미루게 되었다.</p>
</li>
<li><p>배경 지식 학습을 충분히 하지 않고 구현을 시도한다. -&gt; 이후 주말에 학습 정리를 수정하면서 알게 되었다.. 내가 충분히 학습하지 않고 구현을 했구나... 만약 조금 진정하고 학습을 천천히 하고 구현을 시작했더라면 더 빠르게 구현을 했을지도 모르겠다.</p>
</li>
<li><p>피어 세션에 너무 피곤했다. -&gt; 5시간을 자고 아침에 피어 세션에 높은 텐션으로 참여하는게 힘들었다.. 또한 약 1시간 아침 러쉬아워 출근길을 통해 학교로 출근을 하자마자 회의를 하는 것도 한 몫하는 것 같다.</p>
</li>
</ol>
<h2 id="🔫-try">🔫 Try</h2>
<ol>
<li><p>배경 지식을 정독하고 진정하고 먼저 찾아보자 서두른다고 더 빨리 할 수 없다는 것을 2주차에 알게 되었으니 계속 리마인드하고 진정하자.</p>
</li>
<li><p>조금 더 일찍 일어나서 학교에 일찍 도착 한 후 여유롭게 회의를 시작해보자 커피도 사고 릴렉스 한 상태에서 회의를 하면 더 좋은 텐션으로 임할 수 있을 것이다.</p>
</li>
<li><p>해설 영상이 나오면 잠시 멈추고 쉬면서 영상을 봐야겠다. 문서화와 마찬가지로 그때그때 하는 습관을 들여야한다. 누구도 미루고 쌓이면 보기 싫을 것이다.. 3주차에는 뭐든 미루지 않는 것을 집중해보자</p>
</li>
</ol>
<p>옛날에 사람들이 왜 테스크를 미루게 되는지에 대한 아티클을 재미있게 읽었던 것이 기억이 나서 다시 찾아봤다! 다시 한번 읽어보면서 나를 점검하고 발전시키자</p>
<p><a href="https://waitbutwhy.com/2013/10/why-procrastinators-procrastinate.html">waitbutwhy</a></p>
<p><a href="https://velog.io/@edwin_/%EB%84%A4%EC%9D%B4%EB%B2%84%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-1%EC%A3%BC%EC%B0%A8-KPT-%ED%9A%8C%EA%B3%A0">네이버부스트캠프 1주차 KPT 회고</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[pub-sub 패턴]]></title>
            <link>https://velog.io/@edwin_/pub-sub-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@edwin_/pub-sub-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Thu, 25 Jul 2024 04:52:43 GMT</pubDate>
            <description><![CDATA[<h1 id="발행-구독-모델-📬">발행-구독 모델 📬</h1>
<p>발행-구독 모델은 비동기 메시징 패러다임입니다.</p>
<blockquote>
<p>재밌는 점은 해당 모델의 역사를 읽어보니 실제로 &quot;뉴스&quot;부 시스템이 시발점이었다. 발행과 구독을 비유한 것이 아니라 실제 그 의미로 개발된 것입니다.</p>
</blockquote>
<p>발행-구독 모델에서 발신자의 메시지는 특정한 수신자가 정해져 있지 않습니다. 대신 발행된 메시지는 정해진 범주에 따라, 각 범주에 대한 구독을 신청한 수신자에게 전달됩니다. 수신자는 발행자에 대한 지식이 없어도 원하는 메시지만을 수신할 수 있습니다. 🎯</p>
<p>필자는 개인적으로 침착맨 예시로 해당 개념을 이해했습니다. 침착맨은 나를 몰라도 됩니다. 정확히 말하면 나는 침착맨을 모릅니다! 그저 유튜브를 통해 간접적으로 알고 있는 것이죠. 즉, 서로의 존재를 알 필요가 없습니다. 그래서 중간에 유튜브 플랫폼만 알고 있으면 됩니다. 침착맨과 나는 느슨한 결합을 할 수 있는 것입니다. 🤝</p>
<br>
다음 사진은 메시지 큐 모델의 동작 구조와 pub/sub 모델의 동작 구조의 모식화를 비교한 것입니다. 🖼️

<p><img src="https://velog.velcdn.com/images/edwin_/post/8edb9cef-897c-42ac-9189-438de880ae48/image.png" alt="메시지 큐와 pub/sub 비교 이미지"></p>
<h2 id="옵저버-패턴과-차이-🔍">옵저버 패턴과 차이 🔍</h2>
<p>옵서버 패턴(observer pattern)은 객체(subject)의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들(observers)의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴입니다. 주로 분산 이벤트 핸들링 시스템을 구현하는 데 사용됩니다. 발행/구독 모델로 알려져 있기도 합니다.</p>
<p>Observer Pattern과 유사하지만, Observer Pattern의 경우에는 observer와 subject가 직접적인 관계를 갖고 있는 것에 반해, pub-sub 패턴의 경우 publisher와 subscriber가 서로를 전혀 몰라도 상관 없다는 차이가 있습니다. 정리하자면 브로커 또는 메시지 브로커 또는 이벤트 버스라고 불리는 제3요소가 있냐 없냐 차이가 있습니다. 🌉</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/5dabf914-3999-4c95-909b-3847570de226/image.png" alt="브로커 시스템 이미지"></p>
<h2 id="사용-목적-및-사례-📈">사용 목적 및 사례 📈</h2>
<p>메시지 큐를 사용하지 않을 경우, 대규모 데이터 처리 및 메시지 전송을 수동으로 구현해야 하므로 복잡도가 증가하며, 구현에도 많은 시간이 소요됩니다. 애플리케이션 간의 통신 또한 동기적으로 이루어지므로 한 애플리케이션이 다른 애플리케이션의 응답을 기다릴 때 애플리케이션의 응답 시간이 증가합니다. 이런 애플리케이션 간의 직접적인 통신은 애플리케이션 간 결합도를 증가시키므로, 변경과 확장도 어렵습니다.</p>
<hr>
<h2 id="참고-자료-📚">참고 자료 📚</h2>
<p><a href="https://velog.io/@minsuk/Publish-Subscribe-%ED%8C%A8%ED%84%B4%EC%95%8C%EB%A6%BC">Publish-Subscribe 패턴 알림</a></p>
<p><a href="https://ko.wikipedia.org/wiki/%EB%B0%9C%ED%96%89-%EA%B5%AC%EB%8F%85_%EB%AA%A8%EB%8D%B8">발행-구독 모델 - 위키백과</a></p>
<p><a href="https://cloud.google.com/solutions/event-driven-architecture-pubsub?hl=ko">Event-driven Architecture with Pub/Sub</a></p>
<p><a href="https://cloud.google.com/pubsub/docs/overview?hl=ko">Google Cloud Pub/Sub 개요</a></p>
<p><a href="https://docs.kakaocloud.com/service/analytics/pub-sub/pub-sub-overview">카카오 클라우드 - Pub/Sub 개요</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[함수형 프로그래밍]]></title>
            <link>https://velog.io/@edwin_/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@edwin_/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Wed, 24 Jul 2024 04:34:58 GMT</pubDate>
            <description><![CDATA[<h1 id="이것도-하나의-패러다임-🚀">이것도 하나의 패러다임 🚀</h1>
<h2 id="프로그래밍-패러다임이란-🤔">프로그래밍 패러다임이란? 🤔</h2>
<p>프로그래밍 패러다임은 소프트웨어 개발에서 사용하는 기본적인 스타일이나 접근 방식을 뜻합니다. 문제를 해결하는 방법과 프로그램의 구조를 결정짓는 중요한 원칙과 개념있고 다양한 프로그래밍 패러다임이 존재하며, 각 패러다임은 특정 유형의 문제 해결에 더 적합한 도구와 방법론을 선택할 수 있습니다.</p>
<p>프로그래밍 패러다임은 크게 두 가지로 나눌 수 있습니다:</p>
<ol>
<li><p><strong>명령형 패러다임 (Imperative Paradigm)</strong>:</p>
<ul>
<li>프로그램이 수행할 작업을 순서대로 명시하는 접근 방식입니다. 상태와 상태 변화를 중심으로 프로그램이 진행됩니다. 주요 패러다임으로는 명령형, 절차적, 객체지향 프로그래밍이 포함됩니다.</li>
</ul>
</li>
<li><p><strong>선언형 패러다임 (Declarative Paradigm)</strong>:</p>
<ul>
<li>프로그램이 무엇을 해야 하는지 명시하고, 어떻게 해야 하는지는 구현 세부 사항으로 남겨두는 접근 방식입니다. 선언형 프로그래밍은 프로그램의 목적을 정의하는 데 중점을 둡니다. 주요 패러다임으로는 함수형, 논리, 선언형 프로그래밍이 포함됩니다.</li>
</ul>
</li>
</ol>
<p>각 패러다임은 개발자가 코드의 구조를 조직하고 문제를 해결하는 데 도움을 주며, 특정 도메인이나 문제 유형에 따라 가장 적합한 패러다임을 선택하는 것이 중요합니다.
프로그래밍에는 여러 패러다임이 있다. 🧩</p>
<ul>
<li>명령형 프로그래밍 (Imperative Programming)</li>
<li>객체지향 프로그래밍 (Object-Oriented Programming, OOP)</li>
<li>함수형 프로그래밍 (Functional Programming)</li>
<li>논리 프로그래밍 (Logic Programming)</li>
<li>선언형 프로그래밍 (Declarative Programming)</li>
<li>절차적 프로그래밍 (Procedural Programming)</li>
<li>이벤트 기반 프로그래밍 (Event-Driven Programming)</li>
<li>반응형 프로그래밍 (Reactive Programming)</li>
<li>비동기 프로그래밍 (Asynchronous Programming)</li>
<li>메타 프로그래밍 (Meta-Programming)</li>
</ul>
<p>저에겐 Java의 객체지향, SQL의 선언형, C의 절차적 프로그래밍이 익숙하네요. 이러한 여러 패러다임 중에 <strong>&quot;함수형 프로그래밍 (Functional Programming)&quot;</strong>에 대해 알아보겠습니다.🌟</p>
<h1 id="그래서-함수형-프로그래밍이-뭐죠-🤓">그래서 함수형 프로그래밍이 뭐죠? 🤓</h1>
<p><img src="https://velog.velcdn.com/images/edwin_/post/c0f0a3dc-d225-488c-acd3-8d28efb74b46/image.png" alt=""></p>
<p>함수형 프로그래밍은 수학적 함수의 개념을 기반으로 하여 프로그래밍 상태 변화와 부작용을 최소화한다는 것에 의의가 있습니다. 함수형 프로그래밍은 다음과 같은 특성이 있습니다.</p>
<h3 id="1-순수-함수를-통한-예측-가능-🌿">1. 순수 함수를 통한 예측 가능 🌿</h3>
<p>순수 함수란 동일한 입력에 대해서 항상 동일한 출력을 반환하는 함수입니다. 그렇기 때문에 코드의 동작이 예측 가능해지고 이를 통해 디버깅과 테스트를 쉽게 만들 수 있습니다.</p>
<h3 id="2-불변성을-통한-부작용-방지-🔒">2. 불변성을 통한 부작용 방지 🔒</h3>
<p>불변성은 데이터가 변하지 않는다는 의미입니다. 데이터가 변하지 않음으로 여러 많은 부작용들을 방지할 수 있고 js같은 멀티 스레드 환경에서 thread safety 즉, race condition을 방지하고 deadlock을 회피 할 수 있으며 원자성을 보장할 수 있다는 이점이 있습니다.</p>
<h3 id="3-고차-함수-🌀">3. 고차 함수 🌀</h3>
<p>고차 함수는 함수를 인자로 받거나 반환하는 함수입니다. 함수형 프로그래밍에서는 함수는 항상 1급 객체로 취급합니다</p>
<blockquote>
<p>1급 객체란?
다음과 같은 객체를 의미한다.</p>
</blockquote>
<ul>
<li>변수나 데이터 구조안에 담을 수 있다.</li>
<li>파라미터로 전달할수 있다.</li>
<li>반환값으로 사용할 수 있다.</li>
<li>할당에 사용된 이름과 무관하게 고유한 구별이 가능하다.</li>
</ul>
<p>함수를 변수에 할당하거나, 다른 함수에 인자로 전달하는 식으로 사용된다. 예시를 보면 쉽게 이해할 수 있다.
예시 : map, filter, reduce가 대표적인 고차 함수이다.</p>
<h3 id="4-클로저-🔐">4. 클로저 🔐</h3>
<p>함수와 그 함수가 선언된 렉시컬 환경(lexical environment)을 함께 저장하여 함수가 생성될 때의 외부 변수와 그 값을 “기억”하는 기능을 의미합니다.
클로저는 함수가 생성될 때의 외부 변수를 포함한 환경을 “닫아”서 함수 내에서 참조할 수 있게 만든 것입니다. 즉, 클로저는 함수와 함수가 선언될 때의 스코프의 조합으로, 함수가 실행되는 시점에 외부 스코프에 접근할 수 있도록 합니다.</p>
<p>이러한 클로저는 함수를 일급 객체로 취급할 수 있도록하고 불변성과 캡슐화, 정보 은닉의 특성을 제공하고 비동기 프로그래밍에서 함수가 호출되는 시점에 필요한 상태나 문맥 정보를 유지하는데 유용하게 사용된다.</p>
<p>필자는 코드 예시를 보는 것이 이해하기 쉬웠기 때문에 파이썬 코드 예시를 들고 왔다.</p>
<p>** 객체지향 프로그래밍의 예시 **</p>
<pre><code class="language-python">class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance

    def deposit(self, amount):
        if amount &gt; 0:
            self.balance += amount

    def withdraw(self, amount):
        if amount &gt; 0 and amount &lt;= self.balance:
            self.balance -= amount

    def get_balance(self):
        return self.balance

# 사용 예시
account = BankAccount()
account.deposit(100)
account.withdraw(50)
print(account.get_balance())  # 출력: 50</code></pre>
<p>** 함수형 프로그래밍의 예시 **</p>
<pre><code class="language-python">def create_account(balance=0):
    return balance

def deposit(account, amount):
    if amount &gt; 0:
        return account + amount
    return account

def withdraw(account, amount):
    if amount &gt; 0 and amount &lt;= account:
        return account - amount
    return account

def get_balance(account):
    return account

# 사용 예시
account = create_account()
account = deposit(account, 100)
account = withdraw(account, 50)
print(get_balance(account))  # 출력: 50</code></pre>
<ol>
<li><p>불변성 유지: 객체지향 코드에서는 balance 속성이 변경되지만, 함수형 코드에서는 새로운 balance 값을 반환하여 상태를 변경하는 대신 상태를 유지합니다. 즉, 각 함수는 상태를 변경하는 대신 새로운 상태를 반환합니다.</p>
</li>
<li><p>순수 함수 사용: 함수형 프로그래밍에서는 각 함수가 동일한 입력에 대해 동일한 출력을 보장하며, 외부 상태를 변경하지 않습니다. deposit, withdraw, get_balance 함수 모두 외부 변수나 상태에 의존하지 않고, 주어진 인수에 따라서만 작동합니다.</p>
</li>
<li><p>캡슐화와 상태 전달: 상태는 함수 호출 간에 전달되며, 상태를 직접 변경하지 않습니다. 상태 변경이 필요하면 새로운 상태를 반환하고, 이 상태를 다음 함수로 전달합니다.</p>
</li>
<li><p>데이터와 함수의 분리: 객체지향 프로그래밍에서는 데이터와 메서드가 객체 내에 함께 정의되지만, 함수형 프로그래밍에서는 데이터와 함수를 분리하여 처리합니다.</p>
</li>
</ol>
<p>다음은 함수형 프로그래밍 검색을 하다가 정말 이해하기 쉬운 예시를 들고 왔다.
예시는 티라미수 케이크를 만드는 레시피를 예시로 했다.</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/433a90cc-cc7a-42bf-9caa-5f762d571024/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/f4a153fa-9f10-475a-a26b-abfa720101f1/image.png" alt=""></p>
<pre><code class="language-javascript">def make_tiramisu(eggs, sugar1, wine, cheese, cream, fingers, espresso, sugar2, cocoa):

    return refrigerate(
        sift(
            assemble(
                fold(
                    beat(
                        whisk( # over steam
                            beat(beat(eggs), sugar1, wine)
                        ), 
                        beat(cheese)
                    ), 
                    whip(cream)
                ), 
                soak2seconds(fingers, dissolve(sugar2, espresso))
            ), 
            cocoa
        )
    )</code></pre>
<p><img src="https://velog.velcdn.com/images/edwin_/post/f229d20d-411b-4c90-895b-6c34b57ce164/image.png" alt=""></p>
<hr>
<h2 id="참고-자료-📚">참고 자료 📚</h2>
<p><a href="https://mangkyu.tistory.com/1%E3%85%87%E3%84%B9%E3%84%B4">https://mangkyu.tistory.com/1%E3%85%87%E3%84%B9%E3%84%B4</a></p>
<p><a href="https://velog.io/@teo/functional-programming-study">https://velog.io/@teo/functional-programming-study</a></p>
<p><a href="https://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbout.html">https://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbout.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[우리는 왜 TDD가 어려운가?]]></title>
            <link>https://velog.io/@edwin_/TDD</link>
            <guid>https://velog.io/@edwin_/TDD</guid>
            <pubDate>Tue, 23 Jul 2024 03:39:22 GMT</pubDate>
            <description><![CDATA[<h1 id="tdd란-무엇인가"><strong>TDD란 무엇인가</strong></h1>
<p>테스트 주도 개발(Test-Driven Development, TDD)은 소프트웨어 개발 방법론의 하나로, 소프트웨어 기능을 개발하기 전에 먼저 테스트 케이스를 작성하는 것입니다. 이는 코드를 작성하기 전에 코드의 결과를 미리 정의하여, 예상된 대로 동작하는지를 확인하는 방식입니다. 개발자라면 정의는 모두 알고 있을 겁니다. 하지만 그것을 지키고 실행하는 것이 힘들죠... 😅</p>
<p>대부분의 개발은 여유로운 상황에서 이루어지지 않습니다. 마감 기한이 있고 리소스의 제한이 있습니다. 이러한 상황에서 구현하기도 촉박한데 테스트를 쉽게 먼저 짜기란 힘들 것입니다. 네... 제가 그래왔습니다. 🤦‍♂️ </p>
<p>TDD는 개발 초기부터 요구사항을 명확히 하고, 개발 속도를 높이는 데 도움이 되지만, 이러한 이점에도 불구하고 일상 업무에 적용하는 것은 쉽지 않습니다.</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/a5665e41-acbb-4671-bd7a-41e44a6f20aa/image.png" alt="TDD">
나는 딱 정규분포의 가운데에 있나보다... 🎯</p>
<h2 id="tdd를-적용하기-어려운-이유">TDD를 적용하기 어려운 이유</h2>
<ul>
<li><strong>기존 개발 습관</strong>: 기존의 코드 작성 습관을 바꾸기 어렵습니다. TDD는 새로운 접근 방식으로, 기존의 개발 방식과 다르게 테스트를 먼저 작성해야 하므로 이를 수용하는 데 시간이 걸립니다. 😖</li>
<li><strong>시간 소모</strong>: 테스트 코드 작성이 실제 코드 작성보다 시간이 많이 걸립니다. 이는 특히 프로젝트 초기에 명확한 요구사항이 없을 때 더욱 두드러집니다. 🕒</li>
<li><strong>테스트 케이스 작성의 어려움</strong>: 명확하고 효과적인 테스트 케이스를 작성하는 것은 쉬운 일이 아닙니다. 종종 테스트를 어떻게 구성할지, 어떤 케이스를 포함해야 할지 고민하게 됩니다. 🤔</li>
<li><strong>테스트 유지보수</strong>: 코드가 변경되면 해당 변경 사항에 맞춰 테스트도 업데이트해야 합니다. 이는 유지보수의 부담을 증가시킬 수 있습니다. 🔄</li>
<li><strong>리소스 부족</strong>: TDD를 실행하기 위한 충분한 인력과 시간이 없으면 효과적으로 진행하기 어렵습니다. 🔋</li>
</ul>
<p>이 외에도 팀의 문화, 프로젝트의 성격, 관리자의 인식 등 여러 요인이 TDD의 도입과 실행을 어렵게 만듭니다. 그러나 이러한 어려움에도 불구하고, TDD는 소프트웨어 개발의 질을 크게 향상시킬 수 있는 방법론입니다.</p>
<p><img src="blob:https://velog.io/8b4d95de-2433-44c0-9b41-b27e99aaf2f7" alt="업로드중..">
나는 테스트 코드 작성에 들인 노력이 이 짤과 같이 느껴졌다.... 😭</p>
<p>모두 내가 지금까지 TDD를 하기 어려웠던 이유들이다.. 그럼에도 우리는 TDD를 배워야, 적용해야 하는 이유는 뭘까? 🤔</p>
<h2 id="그럼에도-tdd가-중요한-이유">그럼에도 TDD가 중요한 이유</h2>
<ul>
<li><strong>코드 품질 개선</strong>: TDD는 더 명확하고 견고한 코드를 작성하게 합니다. 코드를 작성하기 전에 테스트 케이스를 통해 명확한 요구사항을 설정함으로써, 코드가 기대한 대로 작동하는지를 확인할 수 있습니다. 💪</li>
<li><strong>버그 조기 발견</strong>: 개발 초기에 버그를 발견하고 수정할 수 있습니다. 이는 전체적인 개발 속도와 품질을 높이는 데 도움이 됩니다. 🐛</li>
<li><strong>문서화 기능</strong>: 테스트 케이스는 코드의 기능과 의도를 문서화하는 역할을 합니다. 이는 새로운 팀원이나 유지보수 팀이 코드를 이해하는 데 큰 도움이 됩니다. 📜</li>
<li><strong>리팩토링 지원</strong>: 안전하게 코드를 리팩토링할 수 있습니다. 기존의 테스트 케이스는 리팩토링 후에도 기능이 여전히 정상적으로 동작하는지를 확인하는 데 사용됩니다. 🔧</li>
<li><strong>작은 단위 작업</strong>: 테스크를 작은 단위로 쉽게 쪼갤 수 있습니다. 이는 작업을 관리하기 쉽게 만들고, 개발자들이 보다 집중할 수 있도록 도와줍니다. 🔍</li>
<li><strong>협업 촉진</strong>: TDD는 다른 개발자가 코드의 목적과 기능을 쉽게 이해하게 하여, 오픈 소스 프로젝트나 팀 내 협업을 촉진할 수 있습니다. 🌍</li>
</ul>
<p><img src="https://velog.velcdn.com/images/edwin_/post/a50ff273-4b10-4932-9b1b-90967787896d/image.png" alt="TDD 성공"></p>
<h2 id="실제로-tdd를-진행해본-결과">실제로 TDD를 진행해본 결과</h2>
<p>아직 러닝커브에 있는 상황이기 때문에 코드 작성보다 테스크 코드 작성에 더 많은 시간이 들어갔다. 물론 당연한 일이다. 처음 해보는 것이고 익숙하지 않으니까. 하지만 테스트를 통과하고 난 후 내 코드의 의심이 줄었다. 또한 다른 사람에게 코드를 설명할 때 매우 유용했다!! 🎉</p>
<p>나는 아직 작은 프로젝트에는 TDD가 실제로 유용하다고 생각하지 않는다. 하지만 큰 프로젝트에서 내가 겪었던 러닝커브 때문에 진척이 느려져서는 안된다고 생각한다. 지금과 같은 작은 프로젝트에서 연습하면서 나중에 큰 프로젝트에 빛을 발할 수 있다면 그것만으로도 얼마나 가치 있는가. 🌟</p>
<p>작은 프로젝트에서 TDD를 연습함으로써, 큰 프로젝트에서의 적용을 위한 준비를 할 수 있다. 이는 시간이 지나면서 개발자들이 TDD에 익숙해지고, 나아가 큰 규모의 프로젝트에서 더 큰 가치를 창출할 수 있게 한다. 결론적으로, TDD는 초기에는 어렵고 시간이 많이 소요될 수 있지만, 장기적으로 볼 때 소프트웨어 품질과 개발 프로세스를 크게 향상시킬 수 있는 중요한 도구이다.</p>
<hr>
<h2 id="참고-자료">참고 자료</h2>
<p><a href="https://velog.io/@walker/TDDTestCode%EB%8A%94-%EC%99%9C-%ED%95%A0%EA%B9%8C">https://velog.io/@walker/TDDTestCode%EB%8A%94-%EC%99%9C-%ED%95%A0%EA%B9%8C</a></p>
<p><a href="https://development-crow.tistory.com/37">https://development-crow.tistory.com/37</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[js 비동기 처리란 뭘까?]]></title>
            <link>https://velog.io/@edwin_/Day6</link>
            <guid>https://velog.io/@edwin_/Day6</guid>
            <pubDate>Mon, 22 Jul 2024 04:34:16 GMT</pubDate>
            <description><![CDATA[<h1 id="js는-싱글-스레드-언어-🧵">js는 싱글 스레드 언어? 🧵</h1>
<p>다른 언어와 다르게 js는 싱글 스레드 언어이다. 싱글 스레드 언어란 리터럴리하게 스레드가 한개만 있어 한 번에 하나의 작업만 수행할 수 있다. 즉, 순차적으로 one by one해야 한다는 뜻이다. 동기 방식은 직관적이다는 장점이 있지만 응답이 올 때까지 다른 작업을 처리하지 못하고 대기해야 하기 때문에 느리다고 할 수 있다. 🐢</p>
<h1 id="동기에서-비동기로-🔄">동기에서 비동기로 🔄</h1>
<p>앞선 이유 때문에 여러 작업을 동시에 처리하기 위해서 비동기라는 개념을 도입해 동시에 작업할 수 있다. 가장 대표적인 비동기 함수는 </p>
<pre><code class="language-javascript">setTimeout()
fetch()</code></pre>
<p>등을 예시로 들 수 있다.
비동기는 메인 스레드가 작업을 다른 곳으로 전달해서 처리하게 되고 그 작업이 완료되는 시점에 콜백 함수를 받아 실행하는 방식이다. 이는 백그라운드로 작업한다고 볼 수 있다.
<img src="https://velog.velcdn.com/images/edwin_/post/2b076372-0686-4bac-aa4e-db70f52b3d4f/image.png" alt="">
다음 그림과 같이 특정 태스크를 기다리지 않고 동시에 처리하기 때문에 처리 시간이 줄어드는 것을 확인 할 수 있다.</p>
<h1 id="비동기-처리-원리-🔧">비동기 처리 원리 🔧</h1>
<p>Call Stack과 Event Loop에 대해서 먼저 알아야된다.
<img src="https://velog.velcdn.com/images/edwin_/post/df9ff401-3f3a-4d88-a21b-0b33c5537f31/image.png" alt=""></p>
<p>다음 그림을 확인하면 Callback 함수가 Event Loop에 의해서 CallBack Queue에 담기고 다시 싱글 스레드인 Call Stack에 담겨서 콜백 함수가 실행된다.</p>
<h3 id="자바스크립트는-싱글-스레드-언어인데-어떻게-여러-작업들을-동시에-처리할-수-있을까-🤔">자바스크립트는 싱글 스레드 언어인데 어떻게 여러 작업들을 동시에 처리할 수 있을까? 🤔</h3>
<p>자바스크립트의 이벤트 루프와 호출 스택에 대해 배우면서 Call Stack의 우측에 있는 Web APIs를 간과했을 가능성이 크다. 자바스크립트의 콜 스택(Call Stack)은 싱글 스레드로 작동하지만, 서버에 리소스를 요청하거나 파일 입출력, 타이머 대기 작업 등을 처리하는 Web APIs는 멀티 스레드로 작동하기 때문이다. (멀티 스레드가 생소하다면, 백그라운드에서 동시에 작업이 진행된다고 생각하면 된다)</p>
<p>즉, 브라우저라는 소프트웨어가 멀티 스레드 구조를 가지고 있어, 메인 자바스크립트 스레드를 차단하지 않고 다른 스레드를 사용하여 Web API의 작업을 처리하여 동시 처리가 가능하다.</p>
<p>예를 들어, 아래와 같이 3초를 대기하는 setTimeout 비동기 함수와 다른 작업(Task)들이 있을 때, 이 setTimeout 코드는 Web APIs 중 Timer API로 넘어가 3000ms 밀리초를 병렬로 처리하면서, 동시에 메인 콜 스택의 Task1, Task2 등을 처리할 수 있다.</p>
<p>결론적으로, 브라우저는 멀티스레드로 구성되어 있고 비동기 함수 덕분에 이러한 동시 작업 처리가 가능하여 성능을 향상시킬 수 있었다는 점이다.🚀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네이버부스트캠프 1주차 KPT 회고]]></title>
            <link>https://velog.io/@edwin_/%EB%84%A4%EC%9D%B4%EB%B2%84%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-1%EC%A3%BC%EC%B0%A8-KPT-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@edwin_/%EB%84%A4%EC%9D%B4%EB%B2%84%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-1%EC%A3%BC%EC%B0%A8-KPT-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sat, 20 Jul 2024 11:42:35 GMT</pubDate>
            <description><![CDATA[<h3 id="주차-느낀-점">주차 느낀 점</h3>
<p>&quot;문서화가 중요할까?&quot; 학창 시절부터 내가 가진 의문점이었다.</p>
<p>챌린지 과정을 진행하면서 여러 사람이 작성한 문서들을 보면서 문서화 레벨을 체감할 수 있었다.. 컴퓨터 구조를 통해서도 배울 수 있듯이 데이터를 메모리의 어디에 배치하냐에 따라서 성능이 크게 좌지우지될 수 있다. 한두 번 호출은 큰 차이가 안 날 수도 있지만 Long-term 관점에서는 유의미한 차이가 발생할 것이다. 지금까지 내가 공부를 제대로 하지 않았다고 느끼는 주차였다. 나는 남들보다 이해가 빨라서 필기할 필요가 없다고 생각했다. 하지만 이후 문서화를 잘 한 사람은 오래 기억하고 쉽게 꺼낼 수 있었다. </p>
<p>이번 주차를 한마디로 하자면 &quot;내가 가진 학습 습관에서 가장 부족한 점이 무엇인지 알게 된 주차&quot;라고 표현하고 싶다. 나는 너무 젊고 이제 시작인데 이번 기회를 통해 지금이라도 알게 된 게 너무 행운이라고 생각한다. </p>
<p>&quot;인류의 발전의 시작은 종이의 발명이라고 해도 과언이 아닐 것이다. 나의 부스트는 지금부터다.&quot;</p>
<h2 id="☀️-keep">☀️ Keep</h2>
<blockquote>
</blockquote>
<ol>
<li>매일 7:30에 일어나기 -&gt; 아침 잠이 많은 편인데 일주일 주말까지 일찍 일어나니 점점 익숙해지는 것 같아서 너무 좋다. 또한 같은 양의 수면 대비 효율이 많이 상승한다고 느꼈다.</li>
<li>피어 세션 열정적으로 참여하기 -&gt; 마지막 그룹 회고 때 많은 칭찬을 받아서 더 많은 동기부여를 받을 수 있었다.</li>
<li>계속 많이 토론하자 -&gt; 그레이 존에 대한 의문이 생기면 다른 사람들과 많이 그 주제에 대해서 이야기를 나눴었다. 토론을 통해 나의 주관에 대해서 효율적으로 근거를 찾을 수 있었고 다른 사람들의 전혀 다른 접근법을 고려해볼 수 있었다.</li>
</ol>
<h2 id="🆘-problem">🆘 Problem</h2>
<blockquote>
</blockquote>
<ol>
<li>문서화가 아직 많이 서툴어서 시간이 너무 오래 걸리고 가독성 좋은 글을 쓰지 못 한다.</li>
<li>학습 시간이 구현 시간에 비해서 부족해서 남는게 코드 밖에 남지 않았다</li>
<li>슬랙을 통해서 질문하지 못 했다. -&gt; 질문글을 &quot;잘&quot;쓰는법이 너무 어려워서 쓰다가 포기했던 기억이 있다.</li>
</ol>
<h2 id="🔫-try">🔫 Try</h2>
<blockquote>
</blockquote>
<ol>
<li>항상 공유하기 -&gt; <strong>Problem 1</strong> 내가 가진 문제는 매우 높은 확률로 남들도 가졌을 경우가 많다. 내가 공유한 하나의 문서는 다음과 같은 생각보다 큰 효과를 낼 수 있을 것이다. 절약 시간 = (해당 문제를 겪고 있는 사람 * 해당 문제를 해결할 시간) 나의 공유를 통한 기댓값을 과소평가하지 말자.</li>
<li>슬랙에 질문, 답변 많이 해보기 -&gt; <strong>Problem 3</strong> 다른 동료 분들과 재밌는 토론도 해볼 수 있을 것이다.</li>
<li>다른 동료 분들의 학습 정리를 많이 읽어보자. -&gt; <strong>Problem 1</strong> &quot;잘&quot; 작성된 글의 구조나 전달 방식, 나아가 여러 유용한 md 문법도 공부할 수 있을 것이다.</li>
<li>학습 시간과 구현 시간을 정해서 나누어보자 -&gt; <strong>Problem 2</strong> 수료생 밋업에서 해당 질문에 대한 답변을 들을 수 있었다. 시간을 나눔으로써 비율을 지킬 수 있을 것 같다 </li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로세스 메모리 스택, 힙 구조를 알아보자!]]></title>
            <link>https://velog.io/@edwin_/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@edwin_/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Thu, 18 Jul 2024 04:00:03 GMT</pubDate>
            <description><![CDATA[<h1 id="process-memory-structure-🧠">Process Memory Structure 🧠</h1>
<h2 id="overview-📝">Overview 📝</h2>
<p>프로그램이 실행 될 때 우리가 알기도 전에 메모리가 할당 됩니다. 변수 하나를 만들 때 마다 프로그램은 변수를 저장하기 위해 메모리를 할당합니다. 이번 글에는 프로세스 메모리에서 가장 큰 역할을 차지하는 Stack과 Heap에 대해서 집중해 보겠습니다.</p>
<h2 id="what-is-process-memory-🤔">What is Process Memory? 🤔</h2>
<p>일반적인 프로세스의 구조는 다음과 같다.
<img src="https://velog.velcdn.com/images/edwin_/post/e6fd1e0d-88bb-4548-ab19-fef74ea761cf/image.png" alt="">
프로세스는 각자 자기의 공간을 메모리에 가지고 있고 메모리에는 모든 프로그램의 코드와 변수, 다른 모든 allocated storage가 저장된다.
이 자료는 프로세스의 여러 부분 중 메모리에 관해서 이야기해보겠다. </p>
<h2 id="general-memory-layout-🏗️">General Memory Layout 🏗️</h2>
<p><img src="https://velog.velcdn.com/images/edwin_/post/b5952522-dab0-4157-a0de-cb0b0992dfd6/image.png" alt="">
메모리 아케텍쳐를 보면 크게 4가지 영역으로 나눌 수 있다.</p>
<ul>
<li>Stack : 지역 변수</li>
<li>Heap : 동적으로 저장된 데이터</li>
<li>Data Segment : 전역 변수</li>
<li>Text Segment : 실행 코드</li>
</ul>
<p>BSS는 초기화가 안된 전역 변수를 저장하는 영역으로 많은 자료들에서 Data에 합쳐서 개념을 설명한다.
각각의 메모리의 &quot;주소&quot; 바이트를 할당하고 운영체제에 따라 0부터 시작하여 할당 가능한 주소를 찾는다. text,data 그리고 heap은 low address numers 즉, 낮은 주소 부터 채워지고 stack은 higher addresses를 가진다.
컨벤션에 따라 주소는 16진수 숫자로 표현되며 0x00000000부터 0xFFFFFFFF(0x의 의미는 16진수)까지 가질 수 있다.</p>
<h2 id="stack-📚">Stack 📚</h2>
<p>사진에서 보다시피 stack segment는 메모리의 위에 즉, 가장 높은 주소에 위치한다. 함수가 호출될 때 마다, OS는 stack에 메모리를 할당한다. 새로운 지역 변수가 선언되면 함수의 변수를 저장하기 위해 더 많은 스택 메모리를 아래 방향으로 할당하게 된다. 함수 리턴 이후에 해당 함수, 모든 지역 변수가 스택에서 빠지게 된다. <strong>스택 메모리에서의 할당과 해제는 모두 자동적으로 진행된다.</strong></p>
<p>다음 그림은 일련의 과정을 모식화 한 것이다.
<img src="https://velog.velcdn.com/images/edwin_/post/ea376139-9e4d-42ac-9a00-e0f937eb0341/image.png" alt=""></p>
<p>함수의 스택 메모리가 해제된 이후로 해당 영역이 똑같은 형태로 유지됨을 보장 할 수 없다. <strong>가장 흔한 실수 중 하나는 함수 변수를 포인터로 탐아서 부모 함수로 리턴하는 것이다.</strong> 부모 함수가 포인터를 받으면 유효하지 않은 스택 메모리에 언제든 덮어쓰기 할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/32bb2e25-658d-42fe-9c2d-131c3b725f8d/image.png" alt=""></p>
<p>쉽게 예를 들이, Cube 클래스가 getVolum, getSurfaceArea, private width를 가지고 있고, CreateCube가 객체를 생성한다고 가정하자.
main에서 CreateCube를 호출하고 Cube객체를 생성 후 주소를 리턴한다. 리턴이 되면서 해당 객체는 해제되고 메인에서 c-&gt;getVolume을 호출하면 유효하지 않은 즉, 의도하지 않은 영역을 read하게 되는 상황이다.</p>
<h2 id="heap-🏔️">Heap 🏔️</h2>
<p>앞선 문제에서 함수는 스택 변수는 포인터를 return하지 못 하는 문제를 보았다. 이러한 문제를 해결하기 위해 값을 리턴하거나 값을 스택 메모리가 아닌 다른 곳에 저장하는 방법이 있다. 힙 메모리가 그러한 영역이다. <strong>스택과 다르게 힙은 프로그래머에 의해 명시적으로 할당되고 명시적으로 해제하기 전까지 해제되지 않는다.</strong> 그 뜻은 프로그래머의 역량에 따라서 메모리 사용률이 매우 차이가 날 수 있다. 사용하지 않는 메모리를 해제하지 않는 것을 leak(누수)라고 한다. 메모리 누수는 작은 프로그램에겐 큰 일처럼 보이지 않을 수 있지만 오래 실행되는 서버에서는 누수가 느려짐과 충돌을 야기할 수 있다.</p>
<p>다음 그림은 Heap 할당을 모식화 한 것이다.
<img src="https://velog.velcdn.com/images/edwin_/post/5098a9a1-732d-4955-84a2-529b1bd24a0c/image.png" alt=""></p>
<p><strong>해제를 하고 나서 해제한 메모리를 참고하는 포인터를 사용하는 것은 undefined behavior를 야기한다.</strong> 이러한 실수를 줄이기 위해서 해제한 포인터를 해제 하자마자 nullptr로 초기호하는 좋은 습관을 들여야한다.</p>
<h3 id="참고-문헌-📚">참고 문헌 📚</h3>
<p><a href="https://bottomupcs.com/ch05s02.html">Elements of a process
</a>
<a href="https://courses.grainger.illinois.edu/cs225/fa2022/resources/stack-heap/">Stack and Heap Memory
</a>
<a href="https://en.wikipedia.org/wiki/Process_(computing)">Process (computing) Wiki</a>
<a href="https://www.makeuseof.com/memory-allocation-linux/">How Memory Allocation Works on Linux
</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] 컴파일러 Lexer, Parser, Tokenizer은 무엇인가?]]></title>
            <link>https://velog.io/@edwin_/Tokenizer-Tree-%EA%B5%AC%EC%A1%B0%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B6%84%EC%84%9D</link>
            <guid>https://velog.io/@edwin_/Tokenizer-Tree-%EA%B5%AC%EC%A1%B0%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B6%84%EC%84%9D</guid>
            <pubDate>Wed, 17 Jul 2024 03:52:38 GMT</pubDate>
            <description><![CDATA[<h1 id="코드-해석의-핵심-lexer-parser-tokenizer-🚀💻">코드 해석의 핵심: Lexer, Parser, Tokenizer 🚀💻</h1>
<p><img src="https://velog.velcdn.com/images/edwin_/post/766054d1-cd8c-4a58-9705-9d0859c191c7/image.png" alt=""></p>
<h2 id="목차-📚">목차 📚</h2>
<ol>
<li><a href="#tokenizer-%ED%86%A0%ED%81%AC%EB%82%98%EC%9D%B4%EC%A0%80">Tokenizer (토크나이저)</a></li>
<li><a href="#lexer-%EB%A0%89%EC%84%9C">Lexer (렉서)</a></li>
<li><a href="#parser-%ED%8C%8C%EC%84%9C">Parser (파서)</a></li>
<li><a href="#%EC%84%B8-%EC%9A%94%EC%86%8C%EC%9D%98-%EA%B4%80%EA%B3%84">세 요소의 관계</a></li>
<li><a href="#%EC%8B%A4%EC%A0%9C-%ED%99%9C%EC%9A%A9-%EC%82%AC%EB%A1%80">실제 활용 사례</a></li>
<li><a href="#%EA%B2%B0%EB%A1%A0">결론</a></li>
</ol>
<h2 id="tokenizer-토크나이저-🔧">Tokenizer (토크나이저) 🔧</h2>
<p>토크나이저는 입력된 문자열을 의미 있는 단위로 나누는 도구다. 이 &#39;의미 있는 단위&#39;를 우리는 &#39;토큰(token)&#39;이라고 부른다. </p>
<p>토크나이저의 주요 특징은 다음과 같다:</p>
<ol>
<li>공백이나 특수 문자를 기준으로 문자열을 나눈다.</li>
<li>프로그래밍 언어의 키워드, 식별자, 리터럴 등을 구분한다.</li>
<li>코드의 기본 구조를 파악하는 첫 단계다.</li>
</ol>
<p>토크나이저는 텍스트 처리, 자연어 처리, 컴파일러 설계 등 다양한 분야에서 사용된다. 특히 프로그래밍 언어 처리에서는 lexer의 일부로 동작하여 코드를 의미 있는 단위로 나누는 중요한 역할을 수행한다. 🧩</p>
<h2 id="lexer-렉서-🔍">Lexer (렉서) 🔍</h2>
<p>렉서(Lexer)는 토크나이저보다 한 단계 더 나아간 개념이다. 렉서는 토큰화된 입력을 받아 각 토큰의 유형을 식별하고 분류한다. 이 과정을 &#39;어휘 분석(Lexical Analysis)&#39;이라고 부른다.</p>
<p>렉서의 주요 기능은 다음과 같다:</p>
<ol>
<li>토큰의 유형 식별: 각 토큰이 키워드인지, 식별자인지, 숫자인지 등을 판단한다.</li>
<li>심볼 테이블 생성: 프로그램에서 사용된 모든 식별자(변수명, 함수명 등)를 기록한다.</li>
<li>주석 및 공백 처리: 프로그램의 실행과 무관한 요소들을 제거한다.</li>
<li>에러 검출: 잘못된 토큰이나 문법적 오류를 찾아낸다.</li>
</ol>
<p>이렇게 각 토큰의 의미와 역할을 파악하는 것이 렉서의 주요 임무다. 렉서는 컴파일러나 인터프리터의 첫 단계로, 입력된 소스 코드를 파서가 이해할 수 있는 형태로 변환하는 중요한 역할을 한다. 🔢</p>
<h2 id="parser-파서-🧠">Parser (파서) 🧠</h2>
<p>파서(Parser)는 렉서가 생성한 토큰 스트림을 입력으로 받아, 프로그램의 구조를 분석하고 이를 트리 형태로 표현한다. 이 과정을 &#39;구문 분석(Syntactic Analysis)&#39;이라고 한다.</p>
<p>파서의 주요 기능은 다음과 같다:</p>
<ol>
<li>문법 검증: 프로그램이 언어의 문법 규칙을 따르는지 확인한다.</li>
<li>추상 구문 트리(AST) 생성: 프로그램의 구조를 트리 형태로 표현한다.</li>
<li>의미 분석 준비: AST를 기반으로 프로그램의 의미를 분석할 준비를 한다.</li>
<li>에러 보고: 문법적 오류를 발견하고 보고한다.</li>
</ol>
<p>파서는 프로그래밍 언어 처리뿐만 아니라 XML, JSON 같은 데이터 형식의 처리, 자연어 처리 등 다양한 분야에서 활용된다. 파서는 복잡한 구조를 가진 데이터를 이해하고 처리하는 데 필수적인 도구다. 🌳</p>
<h2 id="세-요소의-관계-🔗">세 요소의 관계 🔗</h2>
<p>토크나이저, 렉서, 파서는 서로 밀접하게 연관되어 있으며, 일반적으로 다음과 같은 순서로 동작한다:</p>
<ol>
<li>토크나이저가 입력 문자열을 토큰으로 나눈다.</li>
<li>렉서가 각 토큰의 유형을 식별하고 분류한다.</li>
<li>파서가 토큰 스트림을 받아 프로그램의 구조를 분석하고 AST를 생성한다.</li>
</ol>
<p>이 세 요소는 때로는 명확히 구분되지 않고 하나의 과정으로 통합되기도 한다. 특히 토크나이저와 렉서는 자주 하나의 단계로 취급된다. </p>
<p>이 과정을 통해 컴퓨터는 인간이 작성한 코드를 이해하고 실행할 수 있게 된다. 이는 마치 우리가 외국어 문장을 읽을 때, 단어를 인식하고(토크나이저), 각 단어의 품사를 파악하며(렉서), 전체 문장의 구조와 의미를 이해하는(파서) 과정과 유사하다고 볼 수 있다. 🌐</p>
<h2 id="실제-활용-사례-💼">실제 활용 사례 💼</h2>
<p>토크나이저, 렉서, 파서는 다양한 분야에서 활용된다:</p>
<ol>
<li><p>프로그래밍 언어 컴파일러 및 인터프리터</p>
<ul>
<li>C, Java, Python 등 모든 프로그래밍 언어의 처리 과정에 사용된다.</li>
</ul>
</li>
<li><p>데이터 형식 파싱</p>
<ul>
<li>XML, JSON, YAML 등의 데이터 형식을 처리할 때 사용된다.</li>
</ul>
</li>
<li><p>자연어 처리</p>
<ul>
<li>문장을 분석하고 이해하는 데 사용된다.</li>
</ul>
</li>
<li><p>설정 파일 처리</p>
<ul>
<li>다양한 애플리케이션의 설정 파일을 읽고 해석하는 데 활용된다.</li>
</ul>
</li>
<li><p>쿼리 언어 처리</p>
<ul>
<li>SQL 같은 데이터베이스 쿼리 언어를 해석하는 데 사용된다.</li>
</ul>
</li>
</ol>
<p>이처럼 토크나이저, 렉서, 파서는 우리가 일상적으로 사용하는 많은 소프트웨어의 핵심 기능을 담당하고 있다. 🌟</p>
<h2 id="결론-🎓">결론 🎓</h2>
<p>토크나이저, 렉서, 파서는 프로그래밍 언어 처리의 기본이 되는 중요한 개념이다. 이들은 각각 고유한 역할을 수행하면서도 서로 긴밀히 연계되어 작동한다.</p>
<ul>
<li>토크나이저는 입력을 의미 있는 단위로 나눈다.</li>
<li>렉서는 각 단위의 의미를 파악한다.</li>
<li>파서는 이들을 조합하여 전체적인 구조와 의미를 이해한다.</li>
</ul>
<p>이 과정을 통해 컴퓨터는 인간의 언어로 작성된 코드를 이해하고 실행할 수 있게 된다. 프로그래밍을 배우고 있거나 이미 전문가인 분들 모두에게 이 개념들을 이해하는 것은 매우 중요하다. </p>
<p>앞으로 코드를 작성하거나 읽을 때, 이 세 가지 요소가 어떻게 작동하는지 생각해 보면 프로그래밍에 대한 이해가 한층 더 깊어질 것이다. 여러분의 코딩 여정에 이 지식이 큰 도움이 되기를 바란다! 💻🚀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[M1 M2 M3 Apple Slicon VM UTM linux 설치 오류]]></title>
            <link>https://velog.io/@edwin_/VM-UTM-linux-%EC%84%A4%EC%B9%98-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@edwin_/VM-UTM-linux-%EC%84%A4%EC%B9%98-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Tue, 16 Jul 2024 04:25:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/edwin_/post/942d9f62-d07c-4cf5-9710-4d7721955334/image.png" alt="">
<img src="https://velog.velcdn.com/images/edwin_/post/c61b3173-e516-4fd2-89c0-0f23c0a245c9/image.png" alt=""></p>
<h2 id="🧐-원인-분석">🧐 원인 분석</h2>
<p>이 문제의 핵심은 바로 &#39;아키텍처의 차이&#39;에 있습니다. Mac Apple Silicon은 ARM 아키텍처를 사용하고 있습니다. 그런데 여기서 조금 헷갈리는 부분이 있습니다.
amd64는 x86-64 아키텍처를 나타내며, 이는 Intel과 AMD의 64비트 프로세서를 위한 것입니다.
aarch64는 ARM의 64비트 아키텍처를 나타내며, 이는 ARM의 64비트 프로세서를 위한 것입니다.
즉, ARM64와 aarch64는 같은 것을 의미하지만, 시스템에 따라 다른 이름으로 부르는 것입니다!</p>
<h2 id="🛠-해결-방법">🛠 해결 방법</h2>
<p>자, 그럼 어떻게 이 문제를 해결할 수 있을까요? 답은 간단합니다!
올바른 ISO 파일 다운로드하기:
Ubuntu의 공식 사이트에서 제공하는 일반 ARM64 이미지 대신, aarch64용 ISO 파일을 다운로드해야 합니다.
다운로드 링크:
여러분을 위해 특별한 링크를 준비했습니다! 👇
<a href="https://cdimage.ubuntu.com/daily-live/current/">https://cdimage.ubuntu.com/daily-live/current/</a>
이 링크에서 aarch64에 대한 ISO 파일을 찾아 다운로드하시기 바랍니다.</p>
<h2 id="💡-추가-팁">💡 추가 팁</h2>
<p>설치 과정에서 UTM과 VM 화면의 연결이 잠시 끊길 수 있습니다. 하지만 걱정하지말고  기다리면 다시 연결이 됩니다! 인내심을 가지고 기다려주시기 바랍니다! ⏳😊</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[이모지는 몇 글자일까?]]></title>
            <link>https://velog.io/@edwin_/%ED%95%99%EC%8A%B5-%EC%A0%95%EB%A6%AC-day1</link>
            <guid>https://velog.io/@edwin_/%ED%95%99%EC%8A%B5-%EC%A0%95%EB%A6%AC-day1</guid>
            <pubDate>Mon, 15 Jul 2024 04:59:09 GMT</pubDate>
            <description><![CDATA[<h2 id="이모지는-몇-바이트를-차지하는가-🤔">이모지는 몇 바이트를 차지하는가? 🤔</h2>
<p>항상 ASCII에 있는 문자만 사용했기 때문에 이모지가 어떻게 메모리에 공간을 차지하는지에 대해서는 생각을 해보지 못했습니다. 오늘 코드를 짜다가 이모지가 같은 공간을 차지하고 있다고 착각하여 결과가 많이 다르게 나왔고, 해당 부분을 고려하지 못해서 오류 원인을 찾느라 정말 많은 시간을 투자했습니다. 이모지가 여러 바이트를 차지할 수 있음을 알고 다음에는 주의하도록 하겠습니다! 😊</p>
<p><img src="https://velog.velcdn.com/images/edwin_/post/91d4d818-842e-4945-9c58-dabf13074c63/image.png" alt=""></p>
<h2 id="무엇이-문제였나-🤷♂️">무엇이 문제였나 🤷‍♂️</h2>
<pre><code class="language-javascript">const bookings = room.isBooked.map(slot =&gt; slot ? &quot;🁢🁢&quot; : &quot;xx&quot;).join(&quot;|&quot;);
const morningBookings = bookings.slice(0, 3); // 오전 시간
const afternoonBookings = bookings.slice(4); // 오후 시간</code></pre>
<p>•    bookings 문자열을 분할할 때, 인덱스 범위가 잘못되었음. 이모지는 여러 바이트를 차지할 수 있어, 문자열을 직접 분할할 때 예상치 못한 결과가 나올 수 있다.
•    bookings 문자열을 3과 4의 인덱스에서 자르면서 중간에 이모지가 잘려 출력이 깨졌다.</p>
<pre><code class="language-javascript">const bookings = room.isBooked.map(slot =&gt; slot ? &quot;🁢🁢&quot; : &quot;  &quot;);
const morningBookings = bookings.slice(0, 4).join(&quot;|&quot;); // 오전 시간
const afternoonBookings = bookings.slice(4).join(&quot;|&quot;); // 오후 시간</code></pre>
<p>•    room.isBooked 배열의 각 요소를 이모지 또는 공백 문자열로 변환한 후 join 메서드로 결합하여 오전과 오후 시간대로 나눴다.
•    bookings 배열을 두 번에 걸쳐 slice와 join을 사용하여 오전 시간대(0-3)와 오후 시간대(4-7)로 나누었다. 이렇게 하면 문자열이 잘리지 않고 제대로 출력된다.</p>
<p>기존 코드에서는 문자열을 잘못 분할하여 이모지가 깨지는 문제가 발생했다. 이를 해결하기 위해 map과 join 메서드를 사용하여 문자열을 올바르게 결합하고, 인덱스 범위를 정확하게 지정하여 slice 메서드로 분할함으로써 문제를 해결했다.</p>
<h3 id="utf-8-✨">UTF-8 ✨</h3>
<p>먼저 프로그래밍 언어에서는 UTF-8 인코딩을 사용하기 때문에 해당 개념을 먼저 알아보자 UTF-8은 가변 길이의 문자 인코딩 방식으로, 1바이트에서 4바이트까지의 길이를 가질 수 있다.</p>
<pre><code>•    ASCII 문자 (U+0000 to U+007F): 1바이트
•    라틴어 보충 (U+0080 to U+07FF): 2바이트
•    기본 다국어 평면 (U+0800 to U+FFFF): 3바이트
•    보충 평면 (U+10000 to U+10FFFF): 4바이트</code></pre><p>이모지는 주로 보충 평면에 속하며, UTF-8 인코딩에서는 4바이트를 차지한다. 예를 들어, ‘🁢’ 이모지는 UTF-8 인코딩에서 4바이트를 사용한다.</p>
<pre><code class="language-javascript">function getUTF8Bytes(string) {
    return new TextEncoder().encode(string);
}

const emoji = &quot;🁢&quot;;
const bytes = getUTF8Bytes(emoji);

console.log(`The emoji ${emoji} is represented by ${bytes.length} bytes in UTF-8.`);
console.log(bytes); // 출력된 바이트 배열</code></pre>
<p>해당 코드를 실행시켜 보면 결과는 다음과 같다.</p>
<pre><code class="language-text">The emoji 🁢 is represented by 4 bytes in UTF-8.
Uint8Array(4) [ 240, 159, 129, 162 ]</code></pre>
<h3 id="요약-✍️">요약 ✍️</h3>
<pre><code>•    이모지는 UTF-8 인코딩에서 일반적으로 4바이트를 차지한다.
•    이모지가 여러 바이트를 차지하기 때문에 문자열을 인덱싱할 때 예상치 못한 결과가 발생할 수 있다.
•    이를 해결하기 위해 map과 join 메서드를 사용하여 문자열을 올바르게 조작하는 것이 중요하다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript js Array.reduce() 활용법]]></title>
            <link>https://velog.io/@edwin_/JavaScript-js-Array.reduce-%ED%99%9C%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@edwin_/JavaScript-js-Array.reduce-%ED%99%9C%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Sun, 14 Jul 2024 10:24:51 GMT</pubDate>
            <description><![CDATA[<h1 id="🏆-arrayreduce-활용법-✨">🏆 Array.reduce() 활용법! ✨</h1>
<p><img src="https://velog.velcdn.com/images/edwin_/post/a1059f2f-6d0e-4c35-bc5f-a56c21206060/image.png" alt=""></p>
<p>이번에 네이버 부스트캠프(네부캠) 챌린지 과정을 하면서 js에 대해서 처음 배우는 중입니다. 네부캠 슬랙에서 reduce 함수에 대해서 자료 공유가 올라와서 글을 읽으면서 정리해보았습니다~</p>
<hr>
<h2 id="0-reduce-함수란">0. reduce 함수란??</h2>
<p>Array.reduce()는 배열의 각 요소를 순회하며 누적 값을 계산하는 함수입니다. 이 함수는 콜백 함수와 초기값, 두 가지 매개변수를 받습니다.</p>
<ul>
<li>콜백 함수: (accumulator, currentValue, currentIndex, array) =&gt; { ... }<ul>
<li>accumulator: 누적값</li>
<li>currentValue: 현재 배열 요소</li>
<li>currentIndex: 현재 인덱스 (옵션)</li>
<li>array: 호출된 배열 (옵션)</li>
</ul>
</li>
<li>초기값: 누적값의 초기값</li>
</ul>
<h2 id="1-숫자-합산하기-🧮">1. 숫자 합산하기 🧮</h2>
<p>배열의 모든 숫자를 합산하는 방법입니다. 이 예제는 가장 기본적이지만, 강력한 <code>reduce</code>의 활용법입니다.</p>
<pre><code class="language-javascript">const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, curr) =&gt; acc + curr, 0);
console.log(sum); // 15</code></pre>
<p>reduce 함수는 배열의 모든 숫자를 하나의 값으로 합산하는 데 유용합니다. 콜백 함수 (acc, curr) =&gt; acc + curr에서 acc는 누적값, curr는 현재 배열 요소를 의미합니다. 초기값 0부터 시작하여 각 요소를 누적하여 더해갑니다. 이 방법으로 배열 [1, 2, 3, 4, 5]의 모든 숫자를 합산하여 15를 얻습니다.</p>
<h2 id="2-배열-평탄화-flattening-arrays-📜">2. 배열 평탄화 (Flattening Arrays) 📜</h2>
<p>중첩된 배열을 단일 배열로 만드는 방법입니다.</p>
<pre><code class="language-javascript">const nested = [[1, 2], [3, 4], [5]];
const flattened = nested.reduce((acc, curr) =&gt; acc.concat(curr), []);
console.log(flattened); // [1, 2, 3, 4, 5]</code></pre>
<p>중첩된 배열을 단일 배열로 만드는 데 reduce와 concat을 함께 사용합니다. 콜백 함수에서 현재 배열 요소(curr)를 누적 배열(acc)에 합칩니다. 초기값은 빈 배열 []입니다. 이렇게 하면 배열 [[1, 2], [3, 4], [5]]를 평탄화하여 [1, 2, 3, 4, 5]로 만듭니다.</p>
<p>concat() 함수는 JavaScript에서 배열이나 문자열을 병합하는 데 사용됩니다. 이 함수는 기존 배열이나 문자열을 변경하지 않고, 새로운 배열이나 문자열을 반환합니다.</p>
<h2 id="3-객체-속성으로-그룹화하기-🎨">3. 객체 속성으로 그룹화하기 🎨</h2>
<p>객체 배열을 특정 속성으로 그룹화합니다.</p>
<pre><code class="language-javascript">const people = [
  { name: &#39;Alice&#39;, age: 30 },
  { name: &#39;Bob&#39;, age: 25 },
  { name: &#39;Charlie&#39;, age: 30 }
];
const groupedByAge = people.reduce((acc, curr) =&gt; {
  acc[curr.age] = acc[curr.age] || [];
  acc[curr.age].push(curr);
  return acc;
}, {});
console.log(groupedByAge);
// { 25: [{ name: &#39;Bob&#39;, age: 25 }], 30: [{ name: &#39;Alice&#39;, age: 30 }, { name: &#39;Charlie&#39;, age: 30 }] }</code></pre>
<p>객체 배열을 특정 속성으로 그룹화할 때 reduce를 사용합니다. 여기서는 age 속성으로 그룹화합니다. acc[curr.age] = acc[curr.age] || []는 현재 나이(curr.age)에 해당하는 배열이 없으면 빈 배열을 할당하고, 있으면 그대로 둡니다. 이후 acc[curr.age].push(curr)로 현재 객체를 해당 나이의 배열에 추가합니다. 이렇게 하면 사람들을 나이별로 그룹화할 수 있습니다.</p>
<p>저는 이번에 js에서는 객체에 []연산자를 이용해서 키를 추가하고 값을 할당 할 수 있다는 사실을 처음 알게 되었습니다~
또한 js에서 a = val1 || val2; 이런식으로 사용하면 val1이 undefined인 경우 val2로 초기화 됩니다.</p>
<h2 id="4-맵-만들기-🗺️">4. 맵 만들기 🗺️</h2>
<p>키-값 맵을 생성합니다.</p>
<pre><code class="language-javascript">const people = [
  { id: 1, name: &#39;Alice&#39; },
  { id: 2, name: &#39;Bob&#39; },
  { id: 3, name: &#39;Charlie&#39; }
];
const peopleMap = people.reduce((acc, person) =&gt; {
  acc[person.id] = person;
  return acc;
}, {});
console.log(peopleMap);
// { 1: { id: 1, name: &#39;Alice&#39; }, 2: { id: 2, name: &#39;Bob&#39; }, 3: { id: 3, name: &#39;Charlie&#39; } }</code></pre>
<p>reduce를 사용하여 객체 배열을 맵으로 변환합니다. 여기서 각 객체의 id를 키로 사용합니다. acc[person.id] = person을 통해 각 객체를 맵에 추가합니다. 초기값은 빈 객체 {}입니다. 결과적으로, 사람들을 ID를 키로 가지는 맵으로 변환합니다.</p>
<h2 id="5-발생-빈도-계산-📊">5. 발생 빈도 계산 📊</h2>
<p>배열 내 각 요소의 발생 빈도를 계산합니다.</p>
<pre><code class="language-javascript">const fruits = [&#39;apple&#39;, &#39;banana&#39;, &#39;orange&#39;, &#39;apple&#39;, &#39;orange&#39;, &#39;banana&#39;, &#39;banana&#39;];
const count = fruits.reduce((acc, fruit) =&gt; {
  acc[fruit] = (acc[fruit] || 0) + 1;
  return acc;
}, {});
console.log(count);
// { apple: 2, banana: 3, orange: 2 }</code></pre>
<p>배열 내 각 요소의 발생 빈도를 계산하기 위해 reduce를 사용합니다. 콜백 함수에서 acc[fruit] = (acc[fruit] || 0) + 1로 현재 과일의 빈도를 증가시킵니다. 초기값은 빈 객체 {}입니다. 이를 통해 각 과일의 발생 빈도를 계산하여 객체로 반환합니다.</p>
<h2 id="6-함수-합성-🛠️">6. 함수 합성 🛠️</h2>
<p>함수들을 합성하여 새로운 함수를 만듭니다.</p>
<pre><code class="language-javascript">const compose = (...functions) =&gt; initialValue =&gt;
  functions.reduceRight((value, func) =&gt; func(value), initialValue);

const add5 = x =&gt; x + 5;
const multiply = x =&gt; x * 2;

const composed = compose(add5, multiply);
console.log(composed(10)); // 25</code></pre>
<p>reduce와 reduceRight를 사용하여 함수들을 합성합니다. 함수 합성은 여러 함수를 결합하여 새로운 함수를 만드는 과정입니다. 이 예제에서는 compose 함수를 정의하여 여러 함수를 결합하고, initialValue부터 시작하여 오른쪽에서 왼쪽으로 함수들을 적용합니다.</p>
<p>JavaScript 코드에서 &quot;...&quot;는 &quot;스프레드 연산자(Spread Operator)&quot; 또는 &quot;나머지 매개변수(Rest Parameter)&quot;로 사용됩니다.</p>
<p>스프레드 연산자 (Spread Operator)
스프레드 연산자는 배열 또는 객체를 개별 요소로 분해합니다. 배열이나 객체의 요소를 펼치는 데 사용됩니다.</p>
<pre><code class="language-javascript">const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // arr1의 요소를 개별 요소로 분해하고 새로운 요소 추가
console.log(arr2); // [1, 2, 3, 4, 5]</code></pre>
<p>나머지 매개변수 (Rest Parameter)
나머지 매개변수는 함수의 인수를 배열로 수집합니다. 함수의 매개변수 목록의 나머지 부분을 하나의 배열로 모을 때 사용됩니다.</p>
<pre><code class="language-javascript">function sum(...args) {
  return args.reduce((acc, curr) =&gt; acc + curr, 0);
}

console.log(sum(1, 2, 3, 4)); // 10</code></pre>
<h2 id="7-상태-관리-🔄">7. 상태 관리 🔄</h2>
<p>간단한 상태 관리를 구현합니다.</p>
<pre><code class="language-javascript">const actions = [
  { type: &#39;INCREMENT&#39; },
  { type: &#39;INCREMENT&#39; },
  { type: &#39;DECREMENT&#39; }
];
const initialState = { count: 0 };

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

const finalState = actions.reduce(reducer, initialState);
console.log(finalState); // { count: 1 }</code></pre>
<p>reduce를 사용하여 간단한 상태 관리 시스템을 구현합니다. 상태 변경을 나타내는 액션 배열을 순회하며 상태를 업데이트합니다. reducer 함수는 현재 상태와 액션을 받아 새로운 상태를 반환합니다. 초기값은 { count: 0 }입니다. 액션 배열을 순회하여 최종 상태를 계산합니다.</p>
<h2 id="8-고유-값-생성-🔍">8. 고유 값 생성 🔍</h2>
<p>배열에서 고유한 값을 생성합니다.</p>
<pre><code class="language-javascript">const numbers = [1, 2, 2, 3, 4, 4, 5];
const unique = numbers.reduce((acc, number) =&gt; {
  if (!acc.includes(number)) {
    acc.push(number);
  }
  return acc;
}, []);
console.log(unique); // [1, 2, 3, 4, 5]</code></pre>
<p>배열에서 중복된 값을 제거하고 고유한 값을 얻기 위해 reduce를 사용합니다. 콜백 함수에서 현재 숫자가 누적 배열에 포함되어 있지 않으면 추가합니다. 초기값은 빈 배열 []입니다. 이를 통해 중복을 제거하고 고유한 값들만 남깁니다.</p>
<h2 id="9-평균-계산-📏">9. 평균 계산 📏</h2>
<p>배열의 평균을 계산합니다.</p>
<pre><code class="language-javascript">const numbers = [1, 2, 3, 4, 5];
const average = numbers.reduce((acc, curr, index, array) =&gt; {
  acc += curr;
  if (index === array.length - 1) {
    return acc / array.length;
  }
  return acc;
}, 0);
console.log(average); // 3</code></pre>
<p>배열의 평균을 계산하기 위해 reduce를 사용합니다. 누적값에 현재 값을 더하고, 배열의 마지막 요소일 때 총합을 배열 길이로 나눕니다. 초기값은 0입니다. 이를 통해 배열의 모든 요소의 평균을 계산합니다.</p>
<p>[참고 블로그][id]
[id]: <a href="https://dev.to/mattlewandowski93/arrayreduce-is-goated-1f1j?utm_source=substack&amp;utm_medium=email">https://dev.to/mattlewandowski93/arrayreduce-is-goated-1f1j?utm_source=substack&amp;utm_medium=email</a></p>
]]></description>
        </item>
    </channel>
</rss>