<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>lee_areum.log</title>
        <link>https://velog.io/</link>
        <description>반갑습니다</description>
        <lastBuildDate>Sat, 10 Jan 2026 04:32:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>lee_areum.log</title>
            <url>https://velog.velcdn.com/images/lee_areum/profile/d33aa97f-8f16-415e-a101-1ae650d591af/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. lee_areum.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/lee_areum" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Nginx란 무엇인가]]></title>
            <link>https://velog.io/@lee_areum/Nginx%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@lee_areum/Nginx%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Sat, 10 Jan 2026 04:32:17 GMT</pubDate>
            <description><![CDATA[<p>nginx는 웹 서버의 일종으로 현재 프로젝트에서는 프록시 서버로 사용하는 것 같다.</p>
<p>아니 그럼 웹서버는 뭐고 프록시 서버는 뭐지</p>
<h2 id="웹-서버">웹 서버</h2>
<p>웹 서버는 웹으로부터 HTTP 요청을 받아 정적 리소스를 제공하는 프로그램을 의미한다.
<img src="https://velog.velcdn.com/images/lee_areum/post/7c69ceb3-32bf-4879-97c5-e5b500b47ae3/image.png" alt="https://soultree.inblog.io/server-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%99%80-%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%84%9C%EB%B2%84-%EB%B0%8F-%ED%94%84%EB%A1%9D%EC%8B%9C%EC%97%90-%EA%B4%80%ED%95%B4-19474"></p>
<p>웹서버는 HTTP 요청을 받으면 정적인 콘텐츠(HTML파일, 이미지, CSS, JavaScript 등)를 제공하고</p>
<p>동적인 컨텐츠 제공을 위한 요청을 WAS에 전송한다.</p>
<p>웹 서버에는 대표적으로 Apache Server, Nginx, IIS 가 있다.</p>
<h2 id="was-web-application-server">WAS (Web Application Server)</h2>
<p>아니 그럼 WAS는 무엇인가
<img src="https://velog.velcdn.com/images/lee_areum/post/5f013196-151a-4f92-9a1c-77c0a93c5686/image.png" alt="https://soultree.inblog.io/server-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%99%80-%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%84%9C%EB%B2%84-%EB%B0%8F-%ED%94%84%EB%A1%9D%EC%8B%9C%EC%97%90-%EA%B4%80%ED%95%B4-19474"></p>
<p>WAS(Web Application Server)는 DB 조회나 기타 여러 로직 처리를 위한 동적 컨텐츠 제공을 하는 Application Server이다.</p>
<p>WAS에는 Apache Tomcat, JBoss, Jeus, Web Sphere 등이 있다.</p>
<h2 id="web-server-vs-was">Web Server vs WAS</h2>
<p>근데 WAS에서도 JSP(JavaServer Pages)를 사용하면 웹 페이지를 제공할 수 있지 않은가? 그럼 WAS랑 Web Server는 뭐가 다른거지?</p>
<p>WebServer의 주 개념은 정적 리소스 제공에 최적화된 서버를 의미한다.</p>
<p>WAS에서도 JSP를 사용한다면 웹 페이지를 제공할 수 있지만 WAS의 주 기능은 비즈니스 로직을 수행하는 것이다.</p>
<p>— 옛날에는 WAS에서 모든 작업을 처리했지만 현재는 보안, 효율, 유지보수 등의 이유로 프론트엔드와 백엔드를 분리하는 구조로 사용하고 있다.</p>
<p>요즘 서버 구조</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/5b5d5184-4e3d-4653-bef3-0efb71e6957f/image.png" alt=""></p>
<p>⇒ WAS에 대해서는 더 공부가 필요할 듯</p>
<p>그래 Web이랑 Was 서버에 대해서는 대충 알았다.</p>
<p>그럼 프록시 서버는 뭐지?</p>
<h2 id="프록시-서버">프록시 서버</h2>
<p>프록시 서버는 클라이언트와 서버 사이에서 중계역할을 하는 서버를 의미한다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/f75fd317-8728-474e-9344-abc6cdf1a235/image.png" alt="https://jung-story.tistory.com/117"></p>
<p><a href="https://jung-story.tistory.com/117">https://jung-story.tistory.com/117</a></p>
<h2 id="forward-proxy--reverse-proxy">Forward Proxy &amp; Reverse Proxy</h2>
<p>프록시 서버도 위치가 어디에 있는지에 따라 하는 역할도 바뀐다.</p>
<h3 id="forward-proxy">Forward Proxy</h3>
<p>Forward Proxy는 정방향 프록시라고도 하는데 우리가 주로 이야기하는 프록시, 프록시 서버, 웹 프록시가 이 포워드 프록시를 지칭한다.</p>
<p>Forward Proxy는 클라이언트와 인터넷 사이에 위치하여</p>
<p>사용자가 인터넷 사이트 및 서비스에 요청을 보내면 프록시 서버는 이 요청을 가로채서 사용자 대신 웹 서버와 통신한다.
<img src="https://velog.velcdn.com/images/lee_areum/post/7dbe045e-b3bd-4d25-bd9a-cefd549c8d7d/image.png" alt="https://soultree.inblog.io/server-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%99%80-%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%84%9C%EB%B2%84-%EB%B0%8F-%ED%94%84%EB%A1%9D%EC%8B%9C%EC%97%90-%EA%B4%80%ED%95%B4-19474"></p>
<p>프록시 서버가 없다면 A는 C에 직접 연결하여 요청을 보내지만</p>
<p>정방향 프록시가 설정되면 A 가 B에 요청을 보내고 B가 C에 요청을 전달한다.</p>
<p>C는 B에게 응답하고 B는 A에게 응답을 다시 전달한다.</p>
<p>포워드 프록시 서버로는 Squid, blue Coat, CNTLM 등의 프로그램을 사용한다.</p>
<h3 id="그럼-프록시-서버는-왜-쓰는거지">그럼 프록시 서버는 왜 쓰는거지?</h3>
<p>이 구조를 보면 아니 바로 C에 요청하는게 더 빠르고 쉽지 않나? 라고 생각 할 수도 있다.</p>
<p>하지만 필요하니 프록시 서버라는 개념이 생겼지 않겠는가</p>
<p>프록시 서버는 여러 이유로 사용된다.</p>
<ol>
<li><p>익명성</p>
<p> 프록시 서버를 사용하면 사용자의 IP 대신 프록시 서버의 IP를 사용하기 때문에 사용자의 개인정보를 보호할 수 있다.</p>
</li>
<li><p>보안강화</p>
<p> 보안이 중요한 기관에서는 방화벽을 사용하여 제한된 사용자에게만 액세스 권한을 사용한다.</p>
<p> 프록시 서버를 사용함녀 특정 그룹이나 사용자에게 리소스 권한을 제어할 수 있다.</p>
</li>
<li><p>캐싱
프록시 서버는 캐싱을 제공하여 서버의 부하를 감소시킬 수 있다.</p>
</li>
</ol>
<p>우리는 이러한 사유로 포워드 프록시 서버를 사용한다.</p>
<h2 id="reverse-proxy-server">Reverse Proxy Server</h2>
<p>역방향 프록시는 하나 이상의 웹 서버 앞에서 클라이언트의 요청을 가로채는 서버이다.
<img src="https://velog.velcdn.com/images/lee_areum/post/fdce745b-0151-4f68-8184-aab6ceaeb434/image.png" alt="https://soultree.inblog.io/server-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%99%80-%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%84%9C%EB%B2%84-%EB%B0%8F-%ED%94%84%EB%A1%9D%EC%8B%9C%EC%97%90-%EA%B4%80%ED%95%B4-19474"></p>
<p>역방향 프록시를 사용하지 않으면 D의 모든 요청은 F로 이동하고 F는 D에게 직접 응답을 보낸다.</p>
<p>역 방향 프록시를 사용하여 D의 요청이 E로 이동하고 E는 F에게 요청을 보낸다.</p>
<p>F는 응답을 E에 주고 E는 D에게 응답을 전달한다.</p>
<p>리버스 프록시로는 nginx, apache HTTPD 등을 사용한다.</p>
<h3 id="역방향-프록시-사용-이유">역방향 프록시 사용 이유?</h3>
<ol>
<li><p>로드 밸런싱</p>
<p> 역방향 프록시를 사용하면 단일 서버의 과부하를 방지하기 위해 트래픽을 여러 서버로 분배하는 부하 분산 솔루션을 제공할 수있다.</p>
</li>
<li><p>보안강화</p>
<p> 역방향 프록시를 사용하면 웹 사이트나 서비스에 원본 서버의 ip 주소를 공개하지 않아도된다.</p>
<p> 이 덕분에 외부의 공격으로부터 서버를 보호할 수 있다.</p>
</li>
<li><p>캐싱</p>
<p> 역방향 프록시도 캐싱 기능을 제공할 수 있다.</p>
</li>
<li><p>SSL 암호화</p>
<p> 역방향 프록시는 요청 데이터를 복호화하고 응답데이터를 암호화 하는 기능을 제공할 수 있다.</p>
</li>
</ol>
<p>그리고 개발자들은 로컬 환경에서 개발 시 CORS 에러를 피하기 위해 proxy 서버를 사용하기도 한다.</p>
<p>CORS에러에 대해 간단하게 설명하자면</p>
<h3 id="-cors란-">** CORS란 **</h3>
<p>CORS에러는 브라우저가 보안을 위해 출처와 목적지가 동일한 요청만 가능하도록 제한한 정책이다.</p>
<pre><code class="language-jsx">* 비교하는 출처
HTTPS://www.domain.com:8080
Protocol/Host/Port</code></pre>
<p>하지만 개발자는 프론트와 백엔드를 로컬환경에 동시에 구동시키는 경우가 많다.</p>
<pre><code class="language-jsx">[Client: 80] → [Nginx: 80] → [Spring Boot: 8080]</code></pre>
<p>이 경우 프록시 서버를 사용하면 브라우저에서 직접 서버를 요청하지 않고 프록시 서버에서 로컬 서버에 요청을 하기 때문에 CORS 정책에 위배되지 않는다.</p>
<p>이런 이유로 프록시 서버를 사용하고</p>
<p>필요하다면 포워드, 리버스 프록시 서버 둘다 사용할 수도 있다.</p>
<h2 id="nginx-너는-뭔데">Nginx 너는 뭔데?</h2>
<p>자 다시 원래 궁금증으로 돌아와서</p>
<p>nginx. 너는 뭔데 Web Server도 되고 프록시 서버도 되는건가?</p>
<p>그건 nginx가 애초에 둘 다 가능하도록 설계되었기 때문이다.</p>
<p>그럼 nginx에 대해 다시 정리해보자.</p>
<p><strong>Nginx</strong>는 고성능 웹서버이자 리버스 프록시 서버로 많이 사용되는 오픈소스 소프트웨어이다.</p>
<h3 id="nginx의-특징">Nginx의 특징</h3>
<p>nginx의 특징이라고 하면 비동기 이벤트 기반구조라고 할 수 있다.</p>
<p>nginx 등장 이전에 많이 사용하던 Apache는 </p>
<p>요청이 들어오면 커넥션 형성을 위한 프로세스를 생성하는데</p>
<p>프로세스 생성에는 시간이 많이 필요하기 때문에 미리 프로세스를 만들어 놓는 방식을 사용했다.</p>
<p>새로운 요청이 들어오면 만들어둔 프로세스를 사용하고</p>
<p>그것도 다 사용하면 새로 만들어서 사용한다.</p>
<p>하지만 컴퓨터 보급이 많아지면서 문제가 발생했다.</p>
<p>아파치는 동시 접속 수가 많아 질 수록 리소스(메모리, CPU)에 부담이 많아지는 문제가 있었다.</p>
<p>이를 해결하기 위해 나온 것이 Nginx 이다.</p>
<p>Nginx는 비동기 이벤트 기반구조로 동시에 많은 요청을 처리할 수 있게되었다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/bd73ff32-3944-46ee-b219-56bfe047264e/image.png" alt="https://hstory0208.tistory.com/entry/Nginx%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EA%B3%A0-%EC%99%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94%EA%B0%80-Apache%EC%99%80-%EC%B0%A8%EC%9D%B4%EC%A0%90"></p>
<p>Nginx는 하나의 마스터 프로세스가 여러 워커 프로세스(worker)를 관리하고</p>
<p>각 워커 프로세스는 수천개의 클라이언트 요청을 이벤트 큐(Event Loop)를 통해 비동기적으로 처리한다.</p>
<p>덕분에 Nginx는 요청이 많아도 리소스 부담이 적고 빠르게 동작할 수 있다.</p>
<p>이러한 장점 덕분에 실무에서도 역방향 프록시 서버로 Nginx를 주로 사용한다.</p>
<p>여기까지 Web Server, WAS 서버, 프록시, Nginx까지 공부해봤다.
다음에는 Web과 Was가 분리된 이유에 대해 공부해보고 싶다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배치의 개념과 동작방식]]></title>
            <link>https://velog.io/@lee_areum/%EB%B0%B0%EC%B9%98%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EB%8F%99%EC%9E%91%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@lee_areum/%EB%B0%B0%EC%B9%98%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EB%8F%99%EC%9E%91%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Fri, 28 Nov 2025 17:18:37 GMT</pubDate>
            <description><![CDATA[<p>지금 새로 들어간 프로젝트에서 대부분의 업무가 배치 작업이다.
하지만.. 나는 배치를 다뤄본적이 거의 없다.
그렇기에 배치에 대해 처음부터 다뤄보려고 한다.</p>
<h2 id="배치란-무엇인가">배치란 무엇인가?</h2>
<p>Batch 프로그램은 &quot;대량의 데이터를 처리하는 과정을 자동화하는 프로그램&quot;을 의미한다.
보통 배치는 스케줄러를 이용하여 특정시간에 자동으로 수행되도록 구성한다.</p>
<p>예를들어 회사에서 당신에게 월급을 줄 때
배치를 사용하지 않으면 회사는 매달 월급날 마다 직원들 한명 한명에게 돈을 이체해야한다.
<img src="https://velog.velcdn.com/images/lee_areum/post/83d8defe-c48f-4d1b-9bbf-558fd23e7078/image.png" alt=""></p>
<p>하지만 이를 배치화 하면 월급날, 원하는 시간에 자동으로 월급을 이체하도록 설정할 수 있다.
<img src="https://velog.velcdn.com/images/lee_areum/post/d73ccb2d-d64f-420f-8051-b33f93cb8124/image.png" alt=""></p>
<p>이외에도 대량의 데이터를 백업하거나 데이터를 다른 서버로 옮기는 작업 등을 할 때
사람들이 많이 사용하지 않는 새벽 같은 시간에 프로그램을 돌리게 되는데
이러한 작업을 배치와 스케줄러로 개발을 한다.</p>
<h3 id="스케줄러-scheduler">스케줄러 (Scheduler)</h3>
<p>배치가 일정한 시간 간격으로 반복적으로 수행되거나 특정 시간에 수행되도록 예약해둔 작업을 실행해주는 시스템이다.</p>
<blockquote>
<p><strong>배치</strong>는 대량의 데이터를 일괄처리 하기 위한 프로그램이고 
<strong>스케줄러</strong>는 설정한 시간에 실행되는 작업을 설정할 수 있게하는 프로그램이다.</p>
</blockquote>
<h2 id="배치의-구성요소">배치의 구성요소</h2>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/0ed0909b-7105-42be-9579-6b97ce838c9f/image.png" alt=""></p>
<h3 id="job">Job</h3>
<p>Job은 배치 처리의 하나의 단위를 이르는 말이다.
Job은 Step의 순서를 정의하고 필요하다면 외부로부터 파라미터를 받아서 작업을 수행할 수도 있다.</p>
<h3 id="step">Step</h3>
<p>Step은 Job을 구성하는 최소한의 단위 작업니다.
하나의 Job은 한개 이상의 Step으로 이루어져 있다.</p>
<p>예를 들어 검증계에서 고객 데이터를 조회해서 개발계 DB에 입력하는 배치를 만든다고 한다면
<img src="https://velog.velcdn.com/images/lee_areum/post/669734d3-7e57-4f57-b972-44cab4c76610/image.png" alt=""></p>
<p><strong>Job</strong>은 &quot;검증계_고객_데이터_개발계_이관Job&quot; 으로 이름을 붙일 수 있다.</p>
<p><strong>Step</strong>은 검증계에서 고객 데이터를 조회하는 Step, 조회한 데이터를 개발계 DB에 입력하는 Step
총 2개로 개발할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/0fac3a15-4ab9-453d-b674-a6f31ea836a9/image.png" alt=""></p>
<h2 id="배치의-동작-프로세스">배치의 동작 프로세스</h2>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/ab036ab8-ecaf-4d45-a0e0-91a76f46725c/image.png" alt="">
배치는 기본적으로 아래와 같은 프로세스로 진행된다.</p>
<ol>
<li>Job Launcher로 Job을 실행시킨다.</li>
<li>Job은 하위 Step을 실행시켜 배치처리를 수행한다.</li>
<li>Step에서 데이터를 읽고(Item Reader) 처리하고(Item Processor) 저장(Item Writer)하는 작업을 진행한다.</li>
</ol>
<h2 id="step의-동작방식-chunk와-tasklet">Step의 동작방식 (Chunk와 Tasklet)</h2>
<p>step을 처리하는 방식에는 크게 Chunk 방식과 Tasklet 방식이 있다.</p>
<h3 id="chunk-step">Chunk Step</h3>
<p>Chunk 방식은 하나의 트렌젝션에 여러개의 데이터를 처리하는 방식을 말한다.</p>
<hr>
<p>지금 프로젝트는 DB procedure를 Spring batch로 변경하는 작업을 하는데
proceduer 개념도 처음이라 겸사겸사 알아봤다.</p>
<p><strong>DB Procedure</strong> 
DB Procedure는 데이터베이스에서 실행 가능한 하나 이상의 SQL문을 그룹화한 블록이다.</p>
<pre><code>CREATE PROCEDURE storedProcName @numbers VARCHAR(max), @day DATE
AS
SET NOCOUNT ON;

SELECT something, something2, something3
FROM sometable
WHERE ids in (select value from string_split(@numbers,&#39;,&#39;))
AND day = @day</code></pre><p>말 그대로 쿼리들을 뭉쳐둔 형태로 근래에는 JAVA 배치로 변경되는 추세인 것 같다.</p>
<h3 id="참고자료">참고자료</h3>
<p><a href="https://zzang9ha.tistory.com/423">https://zzang9ha.tistory.com/423</a>
<a href="https://beomsic.tistory.com/entry/Spring-Batch-Chunk-%EC%A7%80%ED%96%A5-%EC%B2%98%EB%A6%AC">https://beomsic.tistory.com/entry/Spring-Batch-Chunk-%EC%A7%80%ED%96%A5-%EC%B2%98%EB%A6%AC</a>
<a href="https://prodo-developer.tistory.com/165">https://prodo-developer.tistory.com/165</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React useContext]]></title>
            <link>https://velog.io/@lee_areum/React-useContext</link>
            <guid>https://velog.io/@lee_areum/React-useContext</guid>
            <pubDate>Sun, 09 Nov 2025 00:32:20 GMT</pubDate>
            <description><![CDATA[<h2 id="usecontext란-무엇인가">useContext란 무엇인가?</h2>
<p>React에서 자식 컴포넌트에게 데이터를 전달하기 위해 사용하는 props는
깊이가 깊어질수록 같은 값을 계속 내려줘야한다. 이를 prop drilling이라고 부른다.</p>
<h3 id="기존-prop-drilling-방식">기존 prop drilling 방식</h3>
<pre><code>// App.js
function App() {
  const theme = &quot;dark&quot;;
  return &lt;Layout theme={theme} /&gt;;
}

export default App;

// Layout.js
function Layout({ theme }) {
  return (
    &lt;div&gt;
      &lt;Home theme={theme} /&gt;
    &lt;/div&gt;
  );
}

export default Layout;

// Home.js
function Home({ theme }) {
  return &lt;div&gt;현재 테마는 {theme} 입니다.&lt;/div&gt;;
}

export default Home;
</code></pre><p>하지만 prop drilling은 깊이가 길어질수록 가독성이 떨어지고 
데이터가 필요없는 중간 컴포넌트도 자식 컴포넌트에게 데이터를 넘겨주기 위해 데이터를 받아야되는 문제가 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/32ab492a-396d-41a2-9a1d-ab35cc9858ec/image.png" alt=""></p>
<p>위 예시에서도 Home에게 theme를 전달하기 위해 Layout도 theme 데이터를 받아야 한다.</p>
<p>useContext는 prop drilling을 하지 않고도 Context Provider에서 제공한 값을 컴포넌트 어디에서나 바로 사용할 수 있도록 하는 기능이다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/03239917-2416-475e-b2b1-8d733c95905c/image.png" alt=""></p>
<h2 id="예시-코드">예시 코드</h2>
<h3 id="context-생성">Context 생성</h3>
<pre><code>// ThemeContext.js
import {createContext} from &#39;react&#39;;
export const ThemeContext = createContext(); </code></pre><h3 id="부모-컴포넌트에서-데이터-제공">부모 컴포넌트에서 데이터 제공</h3>
<pre><code>// App.js
import { ThemeContext } from &quot;./ThemeContext&quot;;

function App() {
  const theme = &quot;dark&quot;;

  return (
    &lt;ThemeContext.Provider value={theme}&gt;
      &lt;Home /&gt;
    &lt;/ThemeContext.Provider&gt;
  );
}

export default App;</code></pre><p>useContext는 Provider로 감싸진 영역 내에서 Context를 공유합니다.</p>
<h3 id="자식-컴포넌트에서-값-사용">자식 컴포넌트에서 값 사용</h3>
<pre><code>import { useContext } from &quot;react&quot;;
import { ThemeContext } from &quot;./ThemeContext&quot;;

function Home() {
  const theme = useContext(ThemeContext);
  return &lt;div&gt;현재 테마는 {theme} 입니다.&lt;/div&gt;;
}

export default Home;</code></pre><h2 id="더-많은-깊이의-컴포넌트">더 많은 깊이의 컴포넌트</h2>
<h3 id="부모-컴포넌트">부모 컴포넌트</h3>
<pre><code>const TextContext = createContext()

export default function App() {

    const [text, setText] = useState(&quot;Hello world&quot;)

    return (
        &lt;div&gt;
            &lt;TextContext.Provider value={text}&gt;
                &lt;Middle&gt;&lt;/Middle&gt;
            &lt;/TextContext.Provider&gt;
        &lt;/div&gt;
    )
}
</code></pre><h3 id="중간-컴포넌트">중간 컴포넌트</h3>
<p>useContext를 사용하면 context의 데이터가 필요 없는 곳에서는 context를 선언하지 않아도 됩니다.</p>
<pre><code>function Middle(){
    return (
        &lt;div&gt;
            &lt;End/&gt;
        &lt;/div&gt;
    )
}</code></pre><h3 id="최하단-컴포넌트">최하단 컴포넌트</h3>
<pre><code>function End(){
    const text = useContext(TextContext);
    return (
        &lt;div&gt;
            {text}
        &lt;/div&gt;
    )
}</code></pre><p>useContext는 prop drilling 대신 데이터를 공유할 수 있는 좋은 방법이지만
provider의 값이 변경될 때마다 하위 컴포넌트가 재랜더링 됩니다.
때문에 다음에 공부해볼 memo와 병행하여 사용하면 더 좋은 성능을 볼 수 습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring boot에서 왜 Dto에 Setter를 금지하는가?]]></title>
            <link>https://velog.io/@lee_areum/Spring-boot%EC%97%90%EC%84%9C-%EC%99%9C-Dto%EC%97%90-Setter%EB%A5%BC-%EA%B8%88%EC%A7%80%ED%95%98%EB%8A%94%EA%B0%80</link>
            <guid>https://velog.io/@lee_areum/Spring-boot%EC%97%90%EC%84%9C-%EC%99%9C-Dto%EC%97%90-Setter%EB%A5%BC-%EA%B8%88%EC%A7%80%ED%95%98%EB%8A%94%EA%B0%80</guid>
            <pubDate>Sat, 25 Oct 2025 04:36:13 GMT</pubDate>
            <description><![CDATA[<p>이번 프록젝트에서 Spring boot + mybatis를 사용하는데
DTO에 Lombok 라이브러리의 Setter를 사용하면 build 오류가 나는 규칙이 있어서
왜 Setter를 금지하고 대신 Builder를 권장할까? 라는 의문에서 이번 공부를 시작했다.</p>
<h2 id="builder-패턴이란">Builder 패턴이란?</h2>
<p>Builder 패턴은 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 해주는 패턴이다.</p>
<p>이게 무슨 뜻이냐?
<img src="https://velog.velcdn.com/images/lee_areum/post/226ad960-7e51-434d-8145-7f31f349504b/image.png" alt=""></p>
<p>개발을 하다보면 생성자에 여러 인수가 들어가야 하는데
많은 매개변수의 순서를 기억하기 어렵고 가독성이 떨어지게 된다.</p>
<p>이 경우 사용하기 좋은 패턴이 Builder 패턴이다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/8108ad8b-adc1-4dc5-af49-57a185eb31b9/image.png" alt=""></p>
<p>Builder 패턴을 사용한다면 각 변수별로 값을 세팅하기 때문에
생성자의 매개변수 순서와 개수를 기억하지 않고 유연하고 가독성 높게
객체를 생성할 수 있다.</p>
<p>다시 정리하지면
객체를 안전하고 가독성 있게 생성하기 위한 디자인 패턴이다.</p>
<h3 id="builder-패턴-구현-방법">Builder 패턴 구현 방법</h3>
<p>해당 내용을 코드로 한 번 봐보자
<img src="https://velog.velcdn.com/images/lee_areum/post/870dd665-5b59-435d-87bd-472c03b3e451/image.png" alt=""></p>
<p>이름, 비밀번호, email의 변수를 가진 USER라는 클래스가 있다고 한다면
이 USER의 Builder는 아래와 같이 만들 수 있다.</p>
<p>먼저 Builder 클래스를 만들고 필드 맴버를 만들고 싶은 User의 맴버 구성과 동일하게 구성한다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/b08591c3-9505-4f54-89ec-8a8edbc8bf47/image.png" alt=""></p>
<p>그리고 각 맴버에 대한 Setter 함수를 구현한다.
<img src="https://velog.velcdn.com/images/lee_areum/post/aa40af12-9db3-4e1c-a701-7df76f22bb80/image.png" alt=""></p>
<p>가독성을 위해 set 키워드를 제외하고 변수명으로 setter 함수를 구성했다.</p>
<p>이때 return this를 하여 Builder 자신을 리턴한다.
이를 통해 매서드 호출 후 연속적으로 빌더 베서드를 체이닝하여 호출할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/8ef1e056-4ac2-41af-b467-4f515809171d/image.png" alt=""></p>
<p>마지막으로 return값으로 원하는 User 객체를 만들어주는 build 함수를 만들어준다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/6f9f24b6-2910-4368-a26a-386df69a6adf/image.png" alt=""></p>
<p>전체 코드는 아래와 같다.
<img src="https://velog.velcdn.com/images/lee_areum/post/9223438e-09e4-4296-b332-a0c0d72e292d/image.png" alt=""></p>
<p>이렇게 만든 Builder 클래스는 아래 코드로 호출할 수 있다.
<img src="https://velog.velcdn.com/images/lee_areum/post/60637389-73e9-48a2-9249-3616d772ba29/image.png" alt=""></p>
<h3 id="builder-패턴의-장점">Builder 패턴의 장점</h3>
<ol>
<li>직관적인 객체 생성과정</li>
</ol>
<p>생성자만 사용하여 객체를 생성하는 경우 변수가 많아지면 많아질 수록 가독성이 떨어진다.
<img src="https://velog.velcdn.com/images/lee_areum/post/674bc9af-d728-4a28-8f6a-2b9001fa7724/image.png" alt="">
하지만 Builder 패턴을 사용하면 직관적으로 어떤 변수에 어떤 값이 설정되는지 한눈에 알 수 있다. 
이로 인해 휴먼에러를 방지할 수 있다.</p>
<p>요즘은 IDE에서 매개변수 미리보기 힌트 기능 들이 있기때문에 조금 나은 편이다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/9db5f598-9079-4c29-9d75-1ea7d958fbdd/image.png" alt="예시 이미지 출처 :Inpa Dev"></p>
<ol start="2">
<li>필요한 데이터만 설정할 수 있다.</li>
</ol>
<p>객체 생성시 값이 없어도 되는 값이 있을 수도 있다.</p>
<p>이럴 경우 생성자를 사용하면 선택 값에 null을 입력해주는 방식 등으로 구현해야한다.
하지만 Builder를 사용하면 선택 변수를 세팅하지 않을 수 있다.
<img src="https://velog.velcdn.com/images/lee_areum/post/88ca2b16-bbcc-4e7b-8e87-668f6bfcebc9/image.png" alt=""></p>
<ol start="3">
<li>불변성을 확보할 수 있다.
Builder를 사용하여 객체를 생성한다면 필요한 객체를 항상 새로 생성하기 때문에 변경가능성이 줄어들어 불변성을 확보할 수 있다.</li>
</ol>
<p>-&gt; 프로젝트에서 Dto에 Setter를 금지하는 것도 동일한 이유이다.</p>
<p>이러한 장점이 있지만 클래스를 생성할 때마다 Builder를 만들 수도 없는 노릇이다.
그래서 사용하는 것이</p>
<h3 id="lombok-라이브러리-builder">Lombok 라이브러리 Builder</h3>
<p>Lombok 라이브러리에 있는 @Builder 어노테이션을 사용하면 간단하게 Builder 패턴을 클래스에 적용할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/55ee07c0-4cfe-4764-af34-071e2fb5aa71/image.png" alt="">
Dto 클래스에 @Builder 어노테이션을 추가하고</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/0a1daaf8-a56d-4e8b-8c48-2174354db8f8/image.png" alt=""></p>
<p>사용하는 곳에서 객체.builder().변수세팅코드.build()로 사용할 수 있다.</p>
<h3 id="참고-링크">참고 링크</h3>
<p><a href="https://velog.io/@2jjong/Spring-Boot-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1%EA%B3%BC-Builder-%ED%8C%A8%ED%84%B4">https://velog.io/@2jjong/Spring-Boot-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1%EA%B3%BC-Builder-%ED%8C%A8%ED%84%B4</a></p>
<p><a href="https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%EB%B9%8C%EB%8D%94Builder-%ED%8C%A8%ED%84%B4-%EB%81%9D%ED%8C%90%EC%99%95-%EC%A0%95%EB%A6%AC">https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%EB%B9%8C%EB%8D%94Builder-%ED%8C%A8%ED%84%B4-%EB%81%9D%ED%8C%90%EC%99%95-%EC%A0%95%EB%A6%AC</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React-Query useQuery와 useMutation]]></title>
            <link>https://velog.io/@lee_areum/React-Query-useQuery%EC%99%80-useMutation</link>
            <guid>https://velog.io/@lee_areum/React-Query-useQuery%EC%99%80-useMutation</guid>
            <pubDate>Sun, 12 Oct 2025 00:45:39 GMT</pubDate>
            <description><![CDATA[<p>이번 프로젝트에서 react, typescript를 사용하는데
react하면 중요하게 여겨지는 라이브러리가 react-query라는 이야기를 들었다.(실제로 이번 프로젝트에서도 사용한다.)</p>
<p>react-query의 핵심 함수 useQuery, useMutation에 대해 알아보려고 한다.</p>
<h1 id="react-query가-무엇인가">React-query가 무엇인가?</h1>
<p>react-query란 &quot;React 애플리케이션에서 서버 상태(Server State)를 효율적으로 관리하기 위한 라이브러리&quot;이다.</p>
<blockquote>
<p>서버 상태(Server State)란?</p>
</blockquote>
<ul>
<li>서버로 부터 가져온 데이터 &lt;-&gt; 클라이언트 상태(useState, useReducer 등)</li>
<li>서버에서 가져온 데이터를 관리하는 API 응답 데이터</li>
</ul>
<p>react-query는 서버 상태(Server State)를 캐싱하고, 자동으로 갱신하며, 상태를 추적한다.
React Component 내부에서 간단하고 직관적으로 API를 사용할 수 있어서 많이 사용한다.
또한 서버 데이터와 클라이언트 데이터(화면 데이터)를 분리해서 관리한다는 점에서 이점이 있다.</p>
<p>추가적인 이점이라면 무한 스크롤 구현이 쉽다는 장점도 있다.
react-query는 getPreviousPageParam, fetchPreviousPage, hasPreviousPage 등 페이지 관련 기능들이 존재해 페이지 관리가 편하다.</p>
<h1 id="usequery란">UseQuery란?</h1>
<p>react-query의 조회용 훅으로
서버에서 데이터를 조회하는 역할을 한다.
주로 GET 요청에 사용하고 조회한 결과를 자동으로 캐싱, 갱신, 중복 요청을 방지한다.</p>
<blockquote>
<p><strong>Hook</strong>이란?</p>
</blockquote>
<ul>
<li>React에서 상태나 생명주기(lifecycle)에 접근하기 위해 사용하는 특별한 함수</li>
<li>ex) useState -&gt; 컴포넌트 상태 관리
useEffect, useRef 등</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/434fee1b-663e-41c0-9bfc-a6a4644f8601/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/fe5d50c3-5260-46c7-9347-6d67a6ef6403/image.png" alt=""></p>
<ul>
<li>queryKey : 쿼리를 구분하는 고유한 값 
배열 형태로 지정한다.</li>
<li>queryFn : 실제 데이터 요청 함수 
data와 error 객체를 반환한다.</li>
<li>staleTime : 캐시가 신선한(fresh) 상태로 유지되는 시간
기본값은 0이다.</li>
<li>enabled : false일 경우 자동 실행하지 않음</li>
</ul>
<h2 id="usequery-동작원리">useQuery 동작원리</h2>
<ol>
<li><p>컴포넌트가 렌더링될 때 자동으로 useQuery가 실행된다. </p>
<pre><code> queryKey: [&quot;user&quot;, userId],</code></pre></li>
<li><p>이때 queryKey를 기준으로 캐시되어 있는 데이터가 있는지 확인한다.</p>
<p>   1-1. 캐시된 데이터가 있으면 데이터의 상태를 확인하고 사용한다.
<img src="https://velog.velcdn.com/images/lee_areum/post/d478ec25-42d5-4a5e-bcda-4535b650e032/image.png" alt=""></p>
<p>   1-2. 캐시된 데이터가 없으면 queryFn을 실행한다.
 <img src="https://velog.velcdn.com/images/lee_areum/post/edfdaa08-cbba-4393-9c18-910d3a969bd5/image.png" alt=""></p>
<pre><code> queryFn: async () =&gt; {
   const res = await axios.get(`/api/users/${userId}`);
   return res.data;
 },</code></pre></li>
<li><p>queryFn 성공시 데이터를 캐시에 저장하고 UI를 업데이트 한다.</p>
</li>
<li><p>네트워크 상태, focus 이벤트(탭 전환). refetch 조건에 따라 자동으로 재요청할 수 있다.</p>
</li>
</ol>
<h3 id="데이터의-신선도">데이터의 신선도</h3>
<p>react-query는 캐시한 데이터의 상태를 fresh(신선), stale(상함)의 상태로 관리한다.
<img src="https://velog.velcdn.com/images/lee_areum/post/f98935bc-f75f-49c5-846e-66e8a65704eb/image.png" alt="">
데이터가 fresh 하다면 캐시하고 데이터가 stale하다면 새로운 데이터를 가져온다.
<img src="https://velog.velcdn.com/images/lee_areum/post/c0df8f41-861c-4d03-a52b-42860dc7d995/image.png" alt="">
이 stale까지 걸리는 시간을 <strong>staleTime</strong> 옵션으로 지정할 수 있고
stale의 여부를 <strong>isStale</strong>로 확인 할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/4bd2336d-47df-494c-90dd-388bf3f5b950/image.png" alt=""></p>
<h1 id="usemutation">useMutation</h1>
<p>서버의 데이터를 변경(POST, PUT, PATCH, DELETE) 하는데 사용하는 데이터 변경용 훅이다.
useQuery와 다르게 결과값을 캐싱하지 않고
성공/실패 시 콜백(onSuccess, onError, onSettled)으로 후처리 할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/e8a7b6e6-b488-4b3a-9fab-e7d1d973f61a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/00b53338-a5bb-4fdc-bc44-37588faf3872/image.png" alt=""></p>
<ul>
<li>mutaitonFn : 실제로 실행되는 비동기 요청 함수</li>
<li>onSuccess : 성공 시 실행할 콜백</li>
<li>onError : 실패시 실행할 콜백</li>
<li>onSettled : 성공/실패 상관없이 항상 실행되는 콜백</li>
</ul>
<h3 id="usemutation-동작원리">useMutation 동작원리</h3>
<ol>
<li>mutate 함수가 호출될 때 mutationFn을 실행한다.
1-1. 요청 성공 시  : onSuccess로 콜백한다.
1-2. 요청 실패 시 : onError로 콜백한다.</li>
</ol>
<p>useQuery, useMutation을 사용하면 비동기 상태 관리가 용이하고
캐시, 상태관리의 자동화를 통해 서버 &lt;-&gt; 클라이언트 간의 데이터 통신을 원활하게 도와준다.</p>
<h3 id="참고">참고</h3>
<p>react-query에서 제공하는 devtools 라이브러리를 사용하면
서버 상태를 시각적으로 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/b58b74af-1620-405f-a160-965d728acc45/image.png" alt=""></p>
<p>실제로 캐시를 날리거나 새로 요청하는 등의 동작도 가능하다.</p>
<p>useMutation 도 mutaiton 탭에서 확인 가능하다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/d543426e-e1d0-4a64-9088-8b8eb94d764b/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SPRING의 ioc(Inversion of Control) 와 DI]]></title>
            <link>https://velog.io/@lee_areum/SPRING%EC%9D%98-iocInversion-of-Control-%EC%99%80-DI</link>
            <guid>https://velog.io/@lee_areum/SPRING%EC%9D%98-iocInversion-of-Control-%EC%99%80-DI</guid>
            <pubDate>Sun, 14 Sep 2025 01:56:25 GMT</pubDate>
            <description><![CDATA[<h1 id="iocinversion-of-control">IOC(Inversion Of Control)</h1>
<p>객체의 생성과 생명주기를 프레임워크(Spring IoC Container)가 담당하게 한다는 개념이다.</p>
<p>IOC를 사용하지 않을 경우 개발자가 <strong>new</strong> 키워드로 객체를 만들고 제어해야 했는데</p>
<pre><code class="language-jsx">// IOC 도입하지 않은 경우
public class TestService {
    private TestRepository repository = new TestRepository();
}</code></pre>
<p>Spring에서는 IOC개념을 도입하여 객체 생성/주입/생명주기를 프레임워크가 관리한다.</p>
<pre><code class="language-jsx">
//IOC 도입한 경우
@Component
public class TestRepository{
    // DB 접근 코드
}

@Component
public class TestService{
    private final TestRepository repository;

    // Spring의 생성자 주입
    @Autowired
    public TestService(TestRepository repository){
        this.repository = repository;
    }
}</code></pre>
<p>이를 통해 코드의 결합도를 낮추고, 유지 보수성을 높인다.</p>
<h1 id="didependency-injection">DI(Dependency Injection)</h1>
<p>객체 간의 의존성을 외부에서 주입하는 방식이다.</p>
<p>객체가 필요로하는 다른 객체를 외부(주로 컨테이너)로부터 주입받아 사용하는 개념이다.</p>
<p>DI는 IOC를 구현하는 하나의 방법이다.</p>
<h2 id="di의-주입-방식">DI의 주입 방식</h2>
<p>DI 주입 방식에는 <strong>생성자 주입, Setter 주입, 필드 주입</strong> 3가지 방식이 있다.</p>
<h3 id="생성자-주입">생성자 주입</h3>
<p>Spring에서 권장하는 방식</p>
<p>생성자의 호출 시점에 의존성을 주입한다.</p>
<pre><code class="language-jsx">@Component
public class OrderService {
    private final PaymentService paymentService;

    @Autowired
    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}</code></pre>
<p>→ 생성자 호출 시점에 1회 호출되므로 주입받은 객체가 변하지 않고, 항상 객체가 주입된다.</p>
<h3 id="setter-주입">Setter 주입</h3>
<p>Setter 주입은 필드 값을 변경하는 Setter를 통해 의존관계를 주입하는 방법이다.</p>
<p>주입받는 객체가 런타임 시점에 변경되어야 할 때 사용한다.</p>
<pre><code class="language-jsx">@Component
public class OrderService {
    private PaymentService paymentService;

    @Autowired
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}</code></pre>
<ul>
<li>Setter 주입으로 런타임 시점에 주입받는 객체가 변경되는 예시</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/e79e8f59-0f6b-430b-90e0-29d432c41a5b/image.png" alt=""></p>
<pre><code class="language-jsx">// 부모
public interface MessageSender {
    void send(String msg);
}

// 자식 1
@Component
public class EmailSender implements MessageSender {
    @Override
    public void send(String msg) {
        System.out.println(&quot;[EMAIL] &quot; + msg);
    }
}

// 자식 2
@Component
public class SmsSender implements MessageSender {
    @Override
    public void send(String msg) {
        System.out.println(&quot;[SMS] &quot; + msg);
    }
}</code></pre>
<p>EmailSender 객체와 SmsSender 객체가 MessageSender를 상속받는 상황일 때</p>
<pre><code class="language-jsx">@Component
public class NotificationService {
    private MessageSender messageSender;

        // Setter 주입
    @Autowired
    public void setMessageSender(MessageSender messageSender) {
        this.messageSender = messageSender;
    }

    public void notify(String msg) {
        messageSender.send(msg);
    }
}</code></pre>
<p>Service에서 MessageSender로 Setter 주입을 선언하고</p>
<pre><code class="language-jsx">@Configuration
public class AppConfig {
    @Bean
    public NotificationService notificationService() {
        NotificationService service = new NotificationService();

        // 운영 환경: EmailSender 주입
        service.setMessageSender(new EmailSender());

        // 상황에 따라 의존성 교체 가능
        // service.setMessageSender(new SmsSender());

        return service;
    }
}</code></pre>
<p>런타임 환경에서 세터 주입으로 주입하는 객체를 변경할 수 있다.</p>
<p>또한 Spring이 주입하는 것이 아니라 Setter를 통해 직접 객체를 주입하므로</p>
<p>테스트 환경에서도 실행 가능하다.</p>
<pre><code class="language-jsx">// 테스트용 Sender 클래스
@Component
public class FakeSender implements MessageSender {
    @Override
    public void send(String msg) {
        System.out.println(&quot;[FAKE] &quot; + msg);
    }
}

// 테스트 코드
public class NotificationServiceTest {
    @Test
    public void testNotify() {
        NotificationService service = new NotificationService();
        service.setMessageSender(new FakeSender()); // 테스트 전용 객체 주입

        service.notify(&quot;테스트 메시지&quot;); 
        // 출력: [FAKE] 테스트 메시지
    }
}</code></pre>
<h3 id="필드-주입">필드 주입</h3>
<p>필드에 바로 의존 관계를 주입하는 방법이다.</p>
<pre><code class="language-jsx">@Component
public class OrderService {
    @Autowired
    private PaymentService paymentService;
}</code></pre>
<p>필드 주입은 코드가 간단하지만 외부에서 접근이 불가능하기 때문에 필드의 객체를 수정할 수 없다.</p>
<p>반드시 DI 프레임워크(Spring Container)가 존재해야 하기에 사용을 지양하도록 권고한다.</p>
<p>필드 주입은 Spring이 직접 필드에 객체를 넣어주는 방식이기 때문에 </p>
<p><strong>외부에서 new를 하거나 테스트 코드에서 직접 주입하는 것이 불가능</strong> 하다.</p>
<pre><code class="language-jsx">public class ReportServiceTest {
    @Test
    public void test() {
        OrderService service = new OrderService ();
        service.generate(); // NullPointerException 발생!
    }
}</code></pre>
<p>이런 식으로 테스트 환경에서는 Spring 컨테이너가 없으므로 의존성 주입이 되지 않기 때문에 <strong>NullPointerException</strong>이 발생한다.</p>
<p>때문에 필드 주입은 사용이 권장되지 않는다.</p>
<h3 id="왜-생성자-주입을-권고하는가">왜 생성자 주입을 권고하는가?</h3>
<pre><code class="language-jsx">// 생성자 주입 코드
@Component
public class TestService{
    private final TestRepository repository;

    // Spring의 생성자 주입
    @Autowired
    public TestService(TestRepository repository){
        this.repository = repository;
    }
}</code></pre>
<ul>
<li>필수 의존성이 null이 될 가능성이 없다.<ul>
<li>객체가 생성될 때 반드시 주입하기 때문에 이후 컴파일/런타임 시점에 오류가 발생하지 않는다.</li>
</ul>
</li>
<li>final 키워드를 사용하기 때문에 한번 주입하면 변경되지 않는다.</li>
<li>DI 프레임워크(Spring 컨테이너) 없이 순수 자바로 테스트가 가능하다.</li>
</ul>
<h3 id="생성자-주입과-setter-주입-테스트-코드-비교">생성자 주입과 Setter 주입 테스트 코드 비교</h3>
<ul>
<li><p>생성자 주입은 테스트 시 간결한 코드로 사용할 수 있다.</p>
<ul>
<li>단순하게 new 키워드 만으로 테스트가 가능하다.</li>
<li>어떤 객체의 의존성이 필요한지 생성자만으로 확인 가능하다 (명확하다.)</li>
</ul>
</li>
<li><p><strong>생성자 주입</strong>의 단위 테스트</p>
</li>
</ul>
<pre><code class="language-jsx">// 생성자 코드
@Component
public class TestService{
    private final TestRepository repository;

    // Spring의 생성자 주입
    @Autowired
    public TestService(TestRepository repository){
        this.repository = repository;
    }
}

// 단위 테스트
public class ServiceTest {
    @Test
    public void test() {
        TestService service = new TestService(new TestRepository ());

        // 테스트 로
    }
}</code></pre>
<ul>
<li><strong>Setter 주입</strong>일 경우 테스트 코드</li>
</ul>
<pre><code class="language-jsx">// 테스트용 Sender 클래스
@Component
public class FakeSender implements MessageSender {
    @Override
    public void send(String msg) {
        System.out.println(&quot;[FAKE] &quot; + msg);
    }
}

// 테스트 코드
public class NotificationServiceTest {
    @Test
    public void testNotify() {
        NotificationService service = new NotificationService();
        service.setMessageSender(new FakeSender()); // 테스트 전용 객체 주입

        service.notify(&quot;테스트 메시지&quot;); 
        // 출력: [FAKE] 테스트 메시지
    }
}</code></pre>
<ul>
<li><strong>필드 주입</strong>일 경우 테스트 코드 실행 불가 → NullPointException</li>
</ul>
<p>또한 생성자 주입은 순환 참조가 발생할 경우 스프링 컨텍스트 초기화 시점에 확인 할 수 있다.</p>
<pre><code class="language-jsx">@Component
public class AService {
    private final BService bService;

    public AService(BService bService) {
        this.bService = bService;
    }
}

@Component
public class BService {
    private final AService aService;

    public BService(AService aService) {
        this.aService = aService;
    }
}
</code></pre>
<p>이렇게 A 서비스와 B 서비스가 서로를 참조하게 될 경우 
순환 참조가 발생하고 StackOverFlowError 가 발생한다.</p>
<p>필드 주입 시 빈 생성 후 주입 시점에서 순환참조를 발생시킨다. </p>
<ul>
<li>순환참조 에레 메시지</li>
</ul>
<pre><code class="language-jsx">Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  AService defined in file [C:\Users\Mang\IdeaProjects\build\classes\java\main\com\mang\example\user\MemberService.class]
↑     ↓
|  BServicedefined in file [C:\Users\Mang\IdeaProjects\build\classes\java\main\com\mang\example\user\UserService.class]
└─────┘</code></pre>
<h3 id="생성자-주입-실행-타임라인">생성자 주입: 실행 타임라인</h3>
<ol>
<li>Spring 컨테이너 시작 → 빈 스캔 → <code>AService</code> 빈 생성 시도</li>
<li><code>AService</code> 생성자에서 <strong><code>BService</code> 필요</strong></li>
<li>Spring → <code>BService</code> 빈 생성 시도</li>
<li><code>BService</code> 생성자에서 <strong><code>AService</code> 필요</strong></li>
<li>다시 <code>AService</code>를 생성하려고 함 → <strong>무한 루프 감지</strong></li>
<li>❌ <code>BeanCurrentlyInCreationException</code> 발생 (컨텍스트 초기화 실패, 앱 실행 불가)</li>
</ol>
<h3 id="필드-주입-실행-타임라인">필드 주입: 실행 타임라인</h3>
<ul>
<li>Spring 컨테이너 시작 → 빈 스캔</li>
<li><code>AService</code> 인스턴스 생성 (아직 <code>bService</code> 미주입)</li>
<li><code>BService</code> 인스턴스 생성 (아직 <code>aService</code> 미주입)</li>
<li>이제 <code>@Autowired</code> 주입 단계 실행<ul>
<li><code>AService</code>에 <code>BService</code> 넣으려 함</li>
<li><code>BService</code>에 다시 <code>AService</code> 넣으려 함</li>
<li>서로 주입하려다 <strong>순환 참조 무한 루프</strong> 발생</li>
</ul>
</li>
<li>❌ <code>BeanCurrentlyInCreationException</code> 또는 <code>StackOverflowError</code> 발생</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Transaction이란? 전파속성과 분산 트랜잭션 처리까지]]></title>
            <link>https://velog.io/@lee_areum/Transaction%EC%9D%B4%EB%9E%80-%EC%A0%84%ED%8C%8C%EC%86%8D%EC%84%B1%EA%B3%BC-%EB%B6%84%EC%82%B0%EC%B2%98%EB%A6%AC%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@lee_areum/Transaction%EC%9D%B4%EB%9E%80-%EC%A0%84%ED%8C%8C%EC%86%8D%EC%84%B1%EA%B3%BC-%EB%B6%84%EC%82%B0%EC%B2%98%EB%A6%AC%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Fri, 22 Aug 2025 14:34:04 GMT</pubDate>
            <description><![CDATA[<p>이번 프로젝트에서 Transaction 관련 가이드를 듣는데 전파 옵션이 어쩌구.. Required, Requires_New.. XA, Non-XA 용어가 많이 들리는데 정말 아무것도 몰라서 답답함을 느꼈다.</p>
<p>그래서 처음부터 이론적으로 정리를 해보고 싶어서
주제로 가져왔다.</p>
<p>Transaction에 대한 개념부터 시작해서
전파 옵션이 뭐고 다중 DB, MSA에서 Transaction을 어떻게 처리하는가까지 이야기를 해보려고 한다.</p>
<h1 id="transaction">Transaction</h1>
<p>자 그럼 Transaction이란 것이 뭐냐.
벡엔드 개발라면 Transaction에 대해 많이 들어봤을 것이다.</p>
<h2 id="transaction이란-무엇인가">Transaction이란 무엇인가</h2>
<p><strong>Transaction</strong>이란?
데이터 변경 작업들을 <strong>논리적 단위</strong>로 묶어서 <strong>전부 성공하거나(Commit), 전부 취소(Rollback)</strong> 하게 하는 메커니즘.</p>
<p>예시를 들어 다시 설명해보겠다.</p>
<p>A가 B에게 100원을 송금해야 한다고 치자.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/f7697ac3-19c0-44f9-b5b4-cc77e4b73c32/image.png" alt=""></p>
<p>A의 통장에서는 100원이 - 되야 하고
B의 통장에서는 100원이 + 되야 한다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/99555ce7-de69-4413-bf20-5e7e5547c8a0/image.png" alt=""></p>
<p>그런데 만약 A의 통장에서 돈이 나갔는데
B의 통장에 돈이 들어오지 않는다면 어떻게 될까?</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/c62b3724-4c5d-4752-8105-8238cfa0cfad/image.png" alt=""></p>
<p>아마 그 은행은 난리가 날 것이다.</p>
<p>이렇게 동시에 성공하거나 실패해야하는 로직을 <strong>트랜잭션</strong>으로 처리를 하는 것이다.</p>
<p>이후 설명하겠지만 이것이 트렌젝션의 특징 중 <strong>원시성(Atomic)</strong>에 해당한다.</p>
<h2 id="transaction의-특징-4가지">Transaction의 특징 4가지</h2>
<p>그렇다면 어떤 경우 트렌젝션을 사용하는가?
그 트렌젝션이 제공하는 성질 4가지를 소개하겠다.</p>
<h3 id="acid-트랜잭션의-4특징">ACID (트랜잭션의 4특징)</h3>
<h4 id="atomicity원자성"><strong>Atomicity(원자성):</strong></h4>
<p>All or Nothing.
Transaction으로 처리하는 로직은 모두 성공하거나 모두 실패해야 한다.</p>
<p>위의 송금예시를 보면</p>
<p>A의 계좌에서 돈을 - 하는데 성공했는데 B의 계좌에 돈을 +하는데 실패했다면 
A의 계좌에서 돈을 -하는 행위를 rollback(원복) 시킨다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/fd4896f7-cd1c-4649-a3c1-4aeb9bdd891e/image.png" alt=""></p>
<p><strong>Commit</strong>은 수정한 데이터(insert, update, delete)를 영구적으로 DB에 저장하는 것이다.
<strong>Rollback</strong>은 Commit하지 않은 수정사항을 트렌젝션을 시작하기 전상태로 되돌리는 명령어 이다.</p>
<h4 id="consistency일관성"><strong>Consistency(일관성):</strong></h4>
<p>무결성 규칙을 깨뜨리지 않는다.</p>
<p>만약 계좌의 잔액은 -가 되면 안된다는 규칙이 있다면 트렌젝션은 해당 규칙을 깨는 커밋을 할 수 없다.</p>
<h4 id="isolation격리성"><strong>Isolation(격리성):</strong></h4>
<p>여러 트랜잭션이 동시에 실행되도 서로 간섭 최소화하여 순차적으로 동작하는 것처럼 보인다.</p>
<p>만약 A의 잔고가 100원이고 A가 B에게 100원을 송금하는데 
거의 동시에 C가 A의 통장에서 100원을 인출하려고 한다면</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/42e11f33-7db8-47da-9aa2-1f02ecac8aa9/image.png" alt=""></p>
<p>A가 B에게 100원을 송금한 후에 C가 인출을 시도하도록 처리를 한다.
(각 트렌젝션을 격리하지 않으면 통장잔고가 -가 될 수 있기 때문에)</p>
<h4 id="durability영속성"><strong>Durability(영속성):</strong></h4>
<p>커밋되면 장애가 나도 결과가 남아야 한다.</p>
<p>만약 A가 B에게 100원 송금을 성공한 직후 서버에 장애가 발생한다면 어떻게 될까?</p>
<p>트렌젝션은 이미 커밋을 완료한 내용이면 서버가 다운되도 커밋 내용이 안전하게 저장된다.
<br>
<br></p>
<h2 id="물리-트렌젝션과-논리-트렌젝션">물리 트렌젝션과 논리 트렌젝션</h2>
<p>그럼 만약 여러개의 트랜젝션 처리가 필요한 경우에는 어떻게 하는 걸까?</p>
<p>트랜잭션이 이미 진행 중일 때, 다른 새로운 트랜젝션이 실행되는 경우 적용하는 규칙을 <strong>전파</strong>라고 한다.</p>
<p>한 트랜잭션 내에서 다른 메서드 호출 시, 새로운 트랜잭션을 시작할지 기존 트랜잭션을 따를지 결정하는 규칙이 <strong>전파 규칙</strong>이다.</p>
<p>전파 규칙에 대해 알기 위해서는 물리 트랜젝션과 논리 트랜젝션을 알아야한다.</p>
<h3 id="물리-트랜잭션-physical-transaction">물리 트랜잭션 (Physical Transaction)</h3>
<p>물리 트랜젝션은 <strong>실제 데이터베이스에</strong> 적용되는 트랜잭션으로 커넥션을 통해 커밋/롤백하는 단위이다.</p>
<h3 id="논리-트랜잭션-logical-transaction">논리 트랜잭션 (Logical Transaction)</h3>
<p>논리 트랜젝션은 애플리케이션(프레임워크) 관점에서 <strong>여러 메서드 호출을 한 덩어리로 다루는 단위</strong>이다.</p>
<p>쉽게 말해 프레임워크가 트랜젝션을 추상화하여 관리하는 것이 논리 트랜젝션이다.</p>
<blockquote>
<p>논리 트랜잭션 ⊇ 물리 트랜잭션</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/b0447aca-2fe7-4a80-b436-c3df0c98fd17/image.png" alt=""></p>
<p>만약 Transactional 메서드 A가 B를 호출하고 B가 C를 호출하는 프로그램이 있고 이것이 하나의 논리 트랜젝션으로 묶여 있다고 할 때</p>
<p>이 A, B, C는 하나의 물리 트랜젝션일 수도 있고 여러개의 물리 트랜젝션일 수도 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/9d63d2f3-2a4d-4943-9fd4-a5f450fd8961/image.png" alt=""></p>
<p>논리 트랜젝션과 물리 트랜젝션 사이에는 아래와 같은 규칙이 있다.</p>
<p>-&gt; 모든 논리 트렌젝션이 커밋되야 물리 트렌젝션을 커밋한다.
-&gt; 하나의 논리 트렌젝션이라도 오류가 나면 물리 트렌젝션도 롤백한다.</p>
<h2 id="트랜잭션-전파-옵션">트랜잭션 전파 옵션</h2>
<p>하나의 논리 트랜젝션이 어떤 물리 트랜젝션으로 구성되는 가를 결정하는 것이 <strong>전파규칙(옵션)</strong>이다.</p>
<p>전파 규칙(옵션)에는 여러가지가 있는데
그 중에서 Required와 Requires_New를 가장 많이 사용한다.</p>
<h4 id="required"><strong>REQUIRED</strong>:</h4>
<p>가장 기본적으로 사용하는 옵션으로, 이미 트랜잭션이 있으면 합류하고 없으면 새로 시작하는 옵션이다.</p>
<p>Requried는 2개의 논리 트렌젝션을 묶어서 하나의 물리 트렌젝션으로 처리한다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/b0447aca-2fe7-4a80-b436-c3df0c98fd17/image.png" alt=""></p>
<p>👉 같은 트랜잭션으로 묶이기 때문에 커밋과 롤백을 함께한다.</p>
<h4 id="requires_new"><strong>REQUIRES_NEW</strong>:</h4>
<p>무조건 새로운 트랜잭션 시작한다. 기존 트랜잭션은 잠시 보류한다.</p>
<p>Requires_New는 2개의 논리 트랜젝션이 별도의 물리 트랜젝션을 가진다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/651de114-91f4-4f35-80a8-60d86261cb64/image.png" alt=""></p>
<p>👉 주로 독립적인 작업 (예: 로그 기록, 메일 발송 등)을 위해 사용한다.</p>
<p>transactional 메서드 A에서 B 메서드를 호출할 때 A의 성공 여부와 상관없이 별도로 B를 실행하고 싶을때 Required_New를 사용한다.</p>
<p>주로 로그성 업무에서 많이 사용하는 것 같다.</p>
<pre><code>&lt;참고&gt; 그 외에 다른 전파 옵션은 아래와 같다.</code></pre><table>
<thead>
<tr>
<th>전파 옵션</th>
<th>의미</th>
<th>물리 트랜잭션 관점</th>
<th>주 용도/주의점</th>
</tr>
</thead>
<tbody><tr>
<td><strong>REQUIRED</strong> (기본)</td>
<td>있으면 합류, 없으면 새로 시작</td>
<td>가능하면 <strong>같은 물리 트랜잭션 공유</strong></td>
<td>호출자/피호출자 <strong>같이 성공/실패</strong></td>
</tr>
<tr>
<td><strong>REQUIRES_NEW</strong></td>
<td><strong>무조건 새로 시작</strong>, 기존은 <strong>일시 중단</strong></td>
<td><strong>새 물리 트랜잭션</strong> 시작</td>
<td>알림/로그처럼 <strong>독립 커밋</strong>이 필요한 작업</td>
</tr>
<tr>
<td><strong>NESTED</strong></td>
<td>기존 트랜잭션 내 <strong>세이브포인트</strong> 생성</td>
<td><strong>같은 물리 트랜잭션</strong> + Savepoint</td>
<td>부분 롤백. DB/플랫폼 지원 필요</td>
</tr>
<tr>
<td><strong>SUPPORTS</strong></td>
<td>있으면 합류, 없으면 <strong>비트랜잭션</strong></td>
<td>상황따라</td>
<td>조회성 로직</td>
</tr>
<tr>
<td><strong>NOT_SUPPORTED</strong></td>
<td>트랜잭션 <strong>일시 중단</strong>, 비트랜잭션으로 실행</td>
<td>중단</td>
<td>장시간 I/O, 외부 호출 등</td>
</tr>
<tr>
<td><strong>MANDATORY</strong></td>
<td>반드시 기존 트랜잭션 필요, 없으면 예외</td>
<td>합류</td>
<td>정책 강제</td>
</tr>
<tr>
<td><strong>NEVER</strong></td>
<td>트랜잭션이 있으면 예외</td>
<td>금지</td>
<td>특정 구간 보호</td>
</tr>
</tbody></table>
<BR>
<BR>
그렇다면 만약 여러개의 db를 하나의 트랜젝션에 연결해야 하는 경우에는 어떻게 처리할까?

<h1 id="분산-트랜젝션">분산 트랜젝션</h1>
<p><strong>분산 트랜젝션</strong>이란?
여러 데이터베이스나 서버에서 동시에 발생해야 하는 작업을 하나의 작업처럼 묶어서 처리하는 기술을 의미한다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/dc4cccc3-d613-428c-8c2a-bbc8e33bb2b4/image.png" alt=""></p>
<p>이렇게 여러 자원(데이터베이스)를 사용할 때 사용하는 트랜잭션을 <strong>전역 트랜잭션(Global Transaction)</strong>이라고 한다.   반댓말은 지역 트랜잭션(Local Transaction)이다.</p>
<p>전역 트랜잭션에서는 주로 <strong>XA</strong> 프로토콜을 사용한다.</p>
<p>XA는 뭐지? 설명해보겠다.</p>
<h2 id="분산-트랜잭션의-구현-방식xa-와-non-xa">분산 트랜잭션의 구현 방식(XA 와 Non XA)</h2>
<p>분산 트랜잭션의 구현방식에는 크게 XA와 Non-XA가 있다.</p>
<h3 id="xaextended-architecture-확장형-아키텍처"><strong>XA(eXtended Architecture, 확장형 아키텍처)</strong></h3>
<p>XA란 2PC (2 Phase commit)을 통한 분산 트랜잭션 처리를 위해 X-Open이라는 곳에서 명시한 표준 프로토콜이다.</p>
<p>그럼 2PC는 뭐냐..</p>
<h4 id="2pc-two-phase-commit">2PC (Two-Phase Commit)</h4>
<p>2PC (Two-Phase Commit)는  prepare -&gt; commit 단계를 거쳐서 
  모든 DB가 커밋가능한지 확인한 후에 여러 리소스를 한번에 커밋하여 원자성을 지키는 방식이다.</p>
<p>이 방식은 원자성은 보장되지만 락이 걸리는 시간이 길어지면 성능이 저하될 수 있다.</p>
<p>레거시 환경에서 주로 사용했던 방식이다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/3c93ad2b-8b70-4c2f-8dbc-c7eb4f4d573e/image.png" alt=""></p>
<p>예를 들어 A가 B에게 100원을 이체한다고 했을 때</p>
<ol>
<li>A의 통장에서 -100원</li>
<li>B의 통장 +100원</li>
</ol>
<p>A의 통장에서 -100원 인출 가능한지 확인(prepare)하고
B의 통장에서 +100원 입금 가능한지 확인(prepare)한다.
만약 둘 다 가능한 경우 각각의 통장에 처리(Commit)하라는 명령을 내린다.</p>
<p>이 때 A 통장과 B 통장은 commit 명령이 올 때까지 다른 트랜잭션이 접근할 수 없도록 Lock인 상태로 대기한다.</p>
<h3 id="non-xa-트랜젝션">Non-XA 트랜젝션</h3>
<p>  Non-XA는 XA 프로토콜을 사용하지 않고 각각의 DB가 독립적으로 트랜잭션을 수행하는 방식이다. MSA에서 많이 사용하는 방식이다.</p>
<p>  이 방식은 성능이 빠르고 구현이 단순하지만 원자성이 보장되지 않을 수 있기 때문에 추가 작업이 필요할 수 있다.</p>
<p>Non-XA 방식에서 원자성을 보장하기 위해 사용하는 것이 <strong>Saga 패턴</strong>이다.</p>
<p>XA 패턴에서는 모든 DB 트랜잭션을 동시에 처리했지만
Saga 패턴에서는 DB 처리를 순차적으로 처리하여 Lock 설정을 하지 않는다.</p>
<p>그 대신 트랜잭션이 실패한다면 전체 트랜잭션을 Rollback 대신 commit 하려했던 로직의 반대 로직으로 커밋 전으로 데이터를 복구하여 최종적 일관성(Eventual Consistency)를 보장하는 방식이다.</p>
<p>이렇게 로직적으로 롤백하는 트랜잭션을 보상 트랜잭션이라고 한다.</p>
<p>예를 들어 A가 B에게 100원을 이체한다고 했을 때</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/377eeac4-1a4f-480d-99f5-be90012c5b0e/image.png" alt=""></p>
<ol>
<li>A의 통장에서 -100원</li>
<li>B의 통장 +100원</li>
</ol>
<p>Saga에서는 1과 2를 순차적으로 처리하는데
만약 1은 성공했는데 2가 실패한다면</p>
<p>  <img src="blob:https://velog.io/94369514-079a-4420-a69a-19e563f36c82" alt="업로드중.."></p>
<p>A의 통장에 +100원을 하여 트랜잭션 시작 시의 상태로 복구한다.
이 때 +100원을 하는 트랜잭션이 보상 트랜잭션이다.</p>
<h2 id="마치며">마치며</h2>
<p>  이번 포스트에서는 트랜잭션이란 무엇인가. 전파방식에 대해 그리고 XA와 Non-XA에 대해 알아봤다.</p>
<p>이번 포스트는 공부하고 싶은 것은 많은데
설명 순서를 정하는데 어려움이 많았다.</p>
<p>  이것도 알아야될거 같고.. 저것도 봐야하는데 해서 이것저것 많이 넣었다가
  조금 중구난방이 된 느낌이 있다.</p>
<p>  그래도 트랜잭션에 대해 한발짝 다가간 것 같은 느낌이다.</p>
<h2 id="참고자료">참고자료</h2>
<p><a href="https://mangkyu.tistory.com/269">https://mangkyu.tistory.com/269</a>
<a href="https://waspro.tistory.com/734">https://waspro.tistory.com/734</a>
<a href="https://ksh-coding.tistory.com/143">https://ksh-coding.tistory.com/143</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[BFF (Backend For Frontend)와 MSA]]></title>
            <link>https://velog.io/@lee_areum/BFF-Backend-For-Frontend</link>
            <guid>https://velog.io/@lee_areum/BFF-Backend-For-Frontend</guid>
            <pubDate>Sat, 19 Jul 2025 15:15:21 GMT</pubDate>
            <description><![CDATA[<p>이번에 시작한 프로젝트에서 3-Tier와 MSA, BFF 구조를 사용하려고 합니다.</p>
<p>3-Tier이전 프로젝트에서 3-Tier와 MSA는 사용해 봤지만 BFF 구조는 처음 보았기에
BFF란 무엇이고 왜 사용하는지, 장단점을 알아보려고 합니다.</p>
<h2 id="bff-backend-for-frontend-패턴이란">BFF (Backend For Frontend) 패턴이란?</h2>
<p>클라이언트(웹, 모바일 등) 별로 최적화된 백엔드 API 계층을 제공하기 위해, 각 프론트엔드에 특화된 백엔드 서비스를 따로 분리한 아키텍처 방식입니다.</p>
<p>BFF 서버는 프론트엔드와 백엔드 사이의 중간 역할을 하며 간단한 요청은 BFF에서 처리하기도 합니다.
<img src="https://velog.velcdn.com/images/lee_areum/post/ae9ae21c-c1ee-4e7c-9508-cebb8fb8ea70/image.png" alt="">
BFF 서버는 주로 Node.js, Express 등을 사용합니다.</p>
<p>BFF를 이해하기 위해서는 MSA를 알고 있으면 도움이 됩니다.</p>
<h3 id="msa-microservices-architecture">MSA (Microservices Architecture)</h3>
<p>반대되는 용어는 Monolithic Archietecture입니다.
기존 하나의 어플리케이션은 하나의 서비스로 운영하던 것과는 반대로</p>
<p>하나의 어플리케이션을 여러 개의 작은 독립 서비스로 나누어 개발, 배포, 운영하는 아키텍처 스타일입니다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/f1e8a5c9-5d4a-4aa9-b261-317d6efcf5d4/image.png" alt=""></p>
<p>주로 백엔드에서 사용하며 
서비스 별로 독립적으로 배포, 개발이 가능하여 유지보수가 용이하다는 장점이 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/0adce3bf-78d2-4512-9eb2-ff2cfcc45e49/image.png" alt=""></p>
<p>하지만 여러 마이크로 서비스에 직접 요청을 해야되어 복잡하다는 단점이 있습니다.
그래서 이전 프로젝트에서는 GATEWAY 서버를 사용하여 분산처리를 했습니다.
<img src="https://velog.velcdn.com/images/lee_areum/post/b20acca4-2c05-43eb-8601-6a26ba99eec6/image.png" alt=""></p>
<h3 id="bff는-왜-사용하는가">BFF는 왜 사용하는가?</h3>
<p>BFF를 사용하는 이유는 여러가지가 있지만 주로 클라이언트별(Web, IOS, Android)에 불필요한 데이터를 보내지 않고 코드를 모듈화 하기 위해 사용합니다.</p>
<p>BFF를 사용한다면 얻을 수 있는 이점은 아래와 같습니다</p>
<ol>
<li>프론트엔드별로 맞춤 대응 가능</li>
</ol>
<ul>
<li>각 클라이언트(Web, iOS, Android 등)가 요구하는 데이터 구조, 응답 포맷, 인증 방식, 성능 요구가 다르다면 BFF에서 이를 대응할 수 있습니다.
<img src="https://velog.velcdn.com/images/lee_areum/post/d4a39645-042f-4fa1-b7c5-29f4c788dcc5/image.png" alt=""></li>
</ul>
<ol start="2">
<li>불필요한 데이터를 숨길 수 있음</li>
</ol>
<ul>
<li>BFF에서 프론트엔드가 필요한 데이터만 분리하여 내려보내 줄 수 있다.</li>
</ul>
<ol start="3">
<li>복잡한 백엔드 호출은 BFF에서 처리할 수 있음</li>
</ol>
<ul>
<li>하나의 기능을 위해 여러 API를 호출해야 할 경우 Front에서는 하나의 API만 호출하고 BFF에서 Backend 호출 처리를 할 수 있습니다.</li>
<li><blockquote>
<p>ex) 상품 조회를 위해 A, B, C api를 호출해야 한다면 BFF에서 D api를 호출하고 BFF에서 A, B, C api 를 호출하여 어떤 API를 호출하는지 Client에서 알지 못하게 제공할 수 있다.<img src="https://velog.velcdn.com/images/lee_areum/post/7bea7b1e-afdb-4dd4-a71f-1610c1e968cf/image.png" alt=""></p>
</blockquote>
</li>
</ul>
<ol start="4">
<li>재사용성이 용이</li>
</ol>
<ul>
<li>자주 사용하는 기능은 BFF에서 모듈화 하여 사용할 수 있습니다.</li>
</ul>
<h3 id="bff의-단점">BFF의 단점</h3>
<p>BFF는 장점도 있지만 장점도 확실합니다.</p>
<ol>
<li>운영 복잡도 증가</li>
</ol>
<ul>
<li>클라이언트마다 BFF를 생성한담녀 관리해야 할 서버 수가 증가하고 운영 비용이 증가합니다.</li>
</ul>
<ol start="2">
<li>중복 로직 발생 가능성</li>
</ol>
<ul>
<li>여러 BFF가 공통 기능(유저 정보 조회, 인증 처리 등)을 담당하면 중복 코드가 발생하기 쉽습니다.</li>
</ul>
<ol start="3">
<li>추가적인 응답 지연 발생 가능성</li>
</ol>
<ul>
<li>Frontend -&gt; BFF -&gt; Backend 사이의 네트워크 홉이 하나 더 발생하기 때문에 불필요하게 처리만 거치고 오히려 응답 속도가 느려질 가능성이 있습니다.</li>
</ul>
<ol start="4">
<li>아키텍처가 과하게 복잡해 질 수 있음</li>
</ol>
<ul>
<li>단순한 프로젝트에 BFF를 도입하면 과한 설계가 될 수 있습니다.</li>
</ul>
<br>
BFF는 이러한 단점이 있기 때문에 규모가 큰 프로젝트에서 모듈화를 잘 하여 사용하는 것이 좋을 것 같습니다.

<p>추가적으로 
BFF와 GATEWAY의 차이점이 궁금해서 조금 더 알아봤는데</p>
<h3 id="bff와-api-gateway의-차이는">BFF와 API GATEWAY의 차이는?</h3>
<p>BFF와 Gateway API는 모두 클라이언트와 백엔드 사이에 위치하고 인증, 라우팅, 요청/응답 변환 등을 수행한다는 공통점이 있지만
API Gateway는 아키텍처적인 관점으로 요청을 필터링하고 정리하는 역할을 하고
BFF는 프론트엔트 친화적으로 데이터를 가공한다는 차이점이 있습니다.</p>
<p>아래는 API Gateway와 BFF의 차이점에 대해 표로 정리한 것입니다.</p>
<table>
<thead>
<tr>
<th>항목</th>
<th><strong>API Gateway</strong></th>
<th><strong>BFF (Backend For Frontend)</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>주 목적</strong></td>
<td>공통 기능을 통합 처리 (인증, 라우팅, 로깅 등)</td>
<td>클라이언트별 맞춤형 백엔드</td>
</tr>
<tr>
<td><strong>설계 대상</strong></td>
<td>모든 클라이언트에 공통 적용</td>
<td>프론트엔드 앱(Web, iOS, Android 등)별 전용</td>
</tr>
<tr>
<td><strong>기능 중심</strong></td>
<td>보안, 인증, 로깅, 트래픽 제어 등 인프라 관점</td>
<td>데이터 가공, 응답 포맷 최적화, 프론트 요구 맞춤</td>
</tr>
<tr>
<td><strong>재사용성</strong></td>
<td>공통 기능이라 모든 클라이언트에 재사용</td>
<td>클라이언트 맞춤이라 전용 로직 포함</td>
</tr>
<tr>
<td><strong>구현 위치</strong></td>
<td>보통 인프라 팀이 관리</td>
<td>프론트엔드와 가까운 백엔드 팀이 관리</td>
</tr>
<tr>
<td><strong>예시</strong></td>
<td>AWS API Gateway, Kong, NGINX 등</td>
<td>bff-web, bff-mobile 같이 프론트별 서버</td>
</tr>
</tbody></table>
<p>API Gateway는 클라이언트가 어떤 종류든 모두 동일하게 처리하지만 BFF는 각자 필요한 데이터만 가공해서 반환할 수 있습니다.
API Gateway와 BFF는 역할이 다르기 때문에 병행하여 사용할 수 있습니다.
<br></p>
<p>지금까지 BFF란 무엇이고 어떤 장단점이 있는지 알아봤습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AWS SAA 공부] AWS 서비스의 기본 구성요소]]></title>
            <link>https://velog.io/@lee_areum/AWS-SAA-%EA%B3%B5%EB%B6%80-AWS-%EC%84%9C%EB%B9%84%EC%8A%A4%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@lee_areum/AWS-SAA-%EA%B3%B5%EB%B6%80-AWS-%EC%84%9C%EB%B9%84%EC%8A%A4%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C</guid>
            <pubDate>Mon, 30 Jun 2025 02:03:00 GMT</pubDate>
            <description><![CDATA[<h3 id="aws-서비스를-왜-사용하는가">AWS 서비스를 왜 사용하는가?</h3>
<p>사용자는 민첩성을 높이고 복잡성과 위험을 감소시키기 위해 AWS 서비스를 사용합니다.
AWS를 사용함으로 인해 얻을 수 있는 효과는 아래와 같습니다.</p>
<ul>
<li>복잡한 관리 작업 감소 : 인프라 확보 및 관리 시간이 줄어듭니다.</li>
<li>혁신 추진 : 자동화 기능 개발, 컨테이너화, 기계 학습 사용 등이 가능해집니다.</li>
<li>원활한 크기 조정 : 수요에 따라 리소스를 확장 또는 축소 할 수 있습니다.</li>
<li>비용 최적화 : 온프라미스로 관리하는 것보다 비용이 효율적입니다.</li>
<li>보안 취약성 최소화</li>
</ul>
<blockquote>
<p><strong>고가용성(High Availability)</strong> : 시스템이 상당히 오랜 기간 동안 지속적으로 정상 운영이 가능한 성질</p>
</blockquote>
<h3 id="azavailability-zones-가용-영역">AZ(Availability Zones, 가용 영역)</h3>
<p>하나 이상의 데이터 센터 group을 가용 영역이라고 합니다.</p>
<h3 id="aws-region리전">AWS Region(리전)</h3>
<p>두개 이상의 AZ로 이뤄진 영역을 리전이라고 합니다.
리전은 서로 격리되어 있습니다.</p>
<h3 id="aws-local-zones">AWS Local Zones</h3>
<p>지연시간을 줄이기 위해 사용하는 작은 Region
실시간 게임, 지연 시간이 짧은 애플리케이션 등에서 사용합니다.</p>
<h3 id="edge-location">Edge Location</h3>
<p>AWS 서비스 요청자에게 가장 가까이 있는 지점으로, 전 세계 주요 도시에서 운영합니다.
edge location은 더 빠른 전송을 위해 콘텐츠 사본을 캐시합니다.
ex) 남미의 S3에 저장된 비디오 파일을 아시아의 고객에게 빠르게 전송할 때 사용</p>
<p>=&gt; Local Zones는 최종 사용자와 더 가까운 곳에 배포하기 위해 사용합니다.
=&gt; Edge Location은 사용자 위치에 상관없이 빠르게 콘텐츠를 전송하기 위해 사용합니다.</p>
<h2 id="aws-well-architected-framework">AWS Well-Architected Framework</h2>
<p>모범 사례에 따라 클라우드 인프라를 구축하는 방식</p>
<h3 id="well-architected-framework-핵심-요소">Well-Architected Framework 핵심 요소</h3>
<ul>
<li>보안 : 다중 인증, 최소 권한의 원칙</li>
<li>성능 효율성 : 지연 시간 감소, 서버리스 아키텍처</li>
<li>비용 최적화 : 효율적인 리소스 사용</li>
<li>운영 우수성 : 코드를 사용한 운영</li>
<li>안정성 : 장애 복구, 수요 증가 처리, 중단 완화</li>
<li>지속 가능성 : 환경 영향 최소화</li>
</ul>
<h3 id="aws-서비스에-접근하는-방법">AWS 서비스에 접근하는 방법</h3>
<ul>
<li><strong>AWS 관리 콘솔</strong>
  AWS 계정을 관리하고 작업을 수행할 수 있는 GUI</li>
<li>** AWS CLI(Command Line Interface)**
  명령줄을 사용하여 AWS 서비스를 관리할 수 있는 도구<ul>
<li><strong>소프트웨어 개발 키트(SDK)</strong>
 소프트웨어 개발 프레임워크를 통해 코드를 사용하여 인프라를 정의하고 프로비저닝 할 수 있음.<blockquote>
<p>AWS에서 사용하는 모든 호출은 *<em>API (HTTP, HTTPS) *</em>방식으로 동작합니다.</p>
</blockquote>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[OAuth의 개념과 동작원리]]></title>
            <link>https://velog.io/@lee_areum/OAuth%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@lee_areum/OAuth%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Fri, 27 Jun 2025 08:05:44 GMT</pubDate>
            <description><![CDATA[<h2 id="oauth란-무엇인가">OAuth란 무엇인가</h2>
<p>내 비밀번호를 직접 넘기지 않고도 다른 앱이 내 데이터에 접근할 수 있도록 <strong>사용자의 접근 권한을 위임하는 표준 프로토콜</strong></p>
<p>예를들어 아래 이미지와 같이</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/884555a3-e913-43a6-80f9-77c381cc54be/image.png" alt=""></p>
<p>우리가 로그인할 때 직접 ID/PW를 입력하지 않고 구글, Apple 등이 사용자의 인증을 처리해주는 것도 OAuth을 기반한 로그인 방식이라고 할 수 있습니다.</p>
<h2 id="왜-oauth를-사용하는가">왜 OAuth를 사용하는가?</h2>
<p>OAuth를 사용하기 이전에는 타사 애플리케이션에 계정 접근 권한을 부여할 때 
사용자가 ID/PW를 직접 제공해야 했습니다.</p>
<p>하지만 ID/PW를 직접 제공하는 방식은 <strong>타사 앱이 사용자의 ID/PW를 저장하거나 중간에 탈취 당할 수도 있고</strong> 해당 ID/PW로 사용자의 모든 권한에 접근 가능하는 등 보안적인 위험이 있었습니다.</p>
<p>이 문제를 해결하기 위해 구글, 야후, 아마존 등읜 각자 인증 시스템을 개발했습니다. </p>
<ul>
<li>Google : AUthSub,  Yahoo -&gt; BBAuth 등</li>
</ul>
<p>하지만 <strong>각 서비스마다 인증방식이 달라</strong> 개발하기에 어려움이 있었고, 보안 유지도 어려웠습니다.
때문에 2007년 여러 회사들이 모여서 <strong>OAuth라는 표준 프로토콜을 만들었습니다.</strong></p>
<p>현재는 2012년에 발표된 <strong>OAuth 2.0</strong> 표준을 주로 사용합니다.</p>
<h2 id="oauth의-핵심-개념들">OAuth의 핵심 개념들</h2>
<h3 id="resource-owner">Resource Owner</h3>
<p>리소스 소유자
애플리케이션이 액세스하려는 계정을 소유한 최종 사용자
위의 예시에서는 로그인 하려는 사용자가 리소스 소유자입니다.</p>
<h3 id="resource-serverapi">Resource Server(API)</h3>
<p>리소스 서버
사용자를 대신하여 보호된 리소스를 저장하는 서버. 
클라이언트로부터 받은 OAuth 토큰을 수락하고 유효성을 검사한 후 리소스 소유자가 공개에 동의한 사용자 데이터를 제공합니다.</p>
<h3 id="client">Client</h3>
<p>고객
액세스를 요청하는 애플리케이션, 웹사이트 API 또는 디바이스를 말합니다.
클라이언트 ID를 제시하여 Authorization Server에 권한 부여를 요청합니다.</p>
<h3 id="authorization-server">Authorization Server</h3>
<p>권한 부여 서버
<strong>Client가 Resource Server의 서비스를 사용할 수 있게 인증하고, 토큰을 발행해주는 서버</strong>
OAuth 프롬포트를 표시하고 사용자가 애플리케이션의 요청을 승인 또는 거부하는 서버입니다.
또한 사용자가 애플리케이션을 승인한 후 액세스 토큰을 부여하는 역할도 합니다.</p>
<h3 id="access-token">Access Token</h3>
<p>액세스 토큰은 API에 인증된 요청을 보낼 때 사용되는 문자열입니다.
사용자가 타사 애플리케이션의 계정 접근을 승인 했음을 나타내고
토큰에는 해당 액세스 기간, 범위, 서버에 필요한 기타 정보가 포함되어 있습니다.</p>
<h2 id="authorization-code-flow">Authorization Code Flow</h2>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/650ee9ce-38c1-4b8e-a541-bd302a0a6dff/image.png" alt=""></p>
<h3 id="12-로그인-요청">1~2. 로그인 요청</h3>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/884555a3-e913-43a6-80f9-77c381cc54be/image.png" alt="">
사용자가 Google로 로그인을 클릭하여 Client에 로그인을 요청한다.
CLient는 Authorization Server에 로그인을 요청하는데 이때 Authorization Server가 제공하는 URL에 <strong>client_id, rediret_url, scope</strong> 등의 매개변수를 쿼리 스트링으로 포함하여 보낸다.</p>
<pre><code>https://인증서버URL/auth?client_id=1234
&amp;redirect_url=client콜백URL
&amp;scope=create+delete</code></pre><ul>
<li>scope : 리소스 서버에서 제공받고 싶은 리소스 목록, 필요한 권한만 요청할 수 있어 최소권환 원칙 구현에 유리합니다.</li>
<li>client_id : Resource Server에 Client를 등록하면 받을 수 있는 id</li>
<li>redirect_url : 인증 성공시 Redirect 되는 URL</li>
</ul>
<h3 id="34-로그인-페이지-제공-idpw-입력">3~4. 로그인 페이지 제공, ID/PW 입력</h3>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/d5f57eb2-4bb2-42f4-b86d-bdfb4ba23763/image.png" alt="">
Google의 로그인 화면으로 ReDirection 된다.</p>
<h3 id="56-authorization-code-전달">5~6. Authorization Code 전달</h3>
<p>로그인 성공시 Authorization Code를 클라이언트에 전달한다.</p>
<ul>
<li>Authorization Code : Client가 Access Token을 획득하기 위해 사용하는 임시 코드
해당 코드의 수명은 일반적으로 1~10분 정도로 매우 짧다.<h3 id="79-access-token-발급">7~9. Access Token 발급</h3>
클라이언트는 받은 Authorization Code를 사용해 Access Token을 받아온다.
Client는 발급받은 Access Token을 저장하고 이후 Resource Server에 접근할 때는 Access Token으로 접근한다.<h3 id="1013-access-token으로-리소스-접근">10~13. Access Token으로 리소스 접근</h3>
해당 토큰으로 Google에서 사용자의 이메일 등 리소스를 받아와서 로그인 처리한다.</li>
</ul>
<h2 id="참고문서">참고문서</h2>
<p><a href="https://www.oauth.com/oauth2-servers/background/">https://www.oauth.com/oauth2-servers/background/</a>
<a href="https://hudi.blog/oauth-2.0/#OAuth-%EB%93%B1%EC%9E%A5-%EB%B0%B0%EA%B2%BD">https://hudi.blog/oauth-2.0/#OAuth-%EB%93%B1%EC%9E%A5-%EB%B0%B0%EA%B2%BD</a>
<a href="https://www.ibm.com/kr-ko/think/topics/oauth">https://www.ibm.com/kr-ko/think/topics/oauth</a>
<br>
추가로 공부하고 싶은 내용</p>
<ul>
<li>OAuth와 JWT의 차이</li>
<li>OAuth와 SSO의 차이</li>
<li>Outh vs SAML vs OpenID Connect</li>
<li>Refresh Token의 만료 정책</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2025.06.15 this의 원리와 예시]]></title>
            <link>https://velog.io/@lee_areum/2025.06.15-this%EC%9D%98-%EC%9B%90%EB%A6%AC%EC%99%80-%EC%98%88%EC%8B%9C</link>
            <guid>https://velog.io/@lee_areum/2025.06.15-this%EC%9D%98-%EC%9B%90%EB%A6%AC%EC%99%80-%EC%98%88%EC%8B%9C</guid>
            <pubDate>Sun, 15 Jun 2025 01:51:54 GMT</pubDate>
            <description><![CDATA[<h2 id="this-바인딩이란">This 바인딩이란?</h2>
<p>this를 사용할 때 어떤 객체를 참조할지 정해주는 것이다.</p>
<p>이 this가 상황에 따라 달라질 수 있기 때문에 무척 헷갈리는데 오늘은 this가 어떻게 결정되는지와 헷갈리는 상황들을 봐 볼 것이다.</p>
<h1 id="상황에-따른-this-바인딩">상황에 따른 this 바인딩</h1>
<h3 id="일반적인-함수-호출동적-바인딩">일반적인 함수 호출(동적 바인딩)</h3>
<p>this 호출 시점에 동적으로 할당됨</p>
<h3 id="화살표-함수정적-바인딩">화살표 함수(정적 바인딩)</h3>
<p>화살표 함수의 바깥 스코프에서 this를 가져온다.</p>
<p>처음 정의될 때 한번만 결정되기 때문에 정적 바인딩</p>
<pre><code class="language-jsx">const obj = {
  name: &quot;A&quot;,
  normalFn: function () { /* 일반적인 함수 호출 */
    console.log(this.name); // &quot;A&quot;
  },
  arrowFn: () =&gt; { /* 화살표 함수 호출 */
    console.log(this.name); // ❌ undefined
  }
};

obj.normalFn(); // &quot;A&quot;
obj.arrowFn();  // undefined → 전역 스코프의 this를 캡처했기 때문</code></pre>
<h2 id="왜-이렇게-동작할까">왜 이렇게 동작할까?</h2>
<p>이걸 알기 위해서는 JS의 Call Stack, 실행 컨텍스트에 대해 알아야 된다.</p>
<p>이전에 JS 클로저에 대해 알아보면서 정리해 둔 내용이 있어 살짝 가져와보겠다.</p>
<p><a href="https://ytlive.tistory.com/359">https://ytlive.tistory.com/359</a></p>
<h3 id="실행-컨텍스트execution-context">실행 컨텍스트<strong>(Execution Context)</strong></h3>
<p>실행 컨텍스트<strong>(Execution Context)란</strong> 실행할 코드에 제공할 환경 정보들을 모아놓은 객체로 </p>
<p>JS 엔진의 Call Stack에 담는 단위이다</p>
<p>실행 컨텍스트에는 변수 객체, 스코프 체인, this 값에 대한 정보가 담겨있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/c7cdb50e-f6b9-4956-932f-f04e3e6d5e41/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/4f41beab-a7d8-42ac-b8bd-c1afb1430f79/image.png" alt=""></p>
<p>처음 프로그램을 실행하면 전역 컨텍스트(Global Context)가 콜스택에 담긴다.</p>
<h3 id="실행-컨텍스트-내부-구조">실행 컨텍스트 내부 구조</h3>
<p>실행 컨텍스트가 어떻게 생겼나 간단히 살펴 보자면</p>
<ul>
<li><strong>Variable Environment (변수 환경)</strong> : 초기화 시점의 변수, 함수 선언 정보 저장<ul>
<li><strong>Environment Record (번수 저장소)</strong> : 실제 식별자와 그 값을 저장하는 공간</li>
<li><strong>Outer Lexical Environment (스코프 체인)</strong> : 상위 스코프(외부 렉시컬 환경)를 참조하여 스코프 체인을 만든다. 
Outer Lexical Environment 은 상위 스코프의 Lexical Environment를 참조한다. 
때문에 현재 스코프에 없는 값이라도 Outer를 타고 올라가서 상위 스코프에 있는 값을 조회할 수 있다.</li>
</ul>
</li>
<li><strong>Lexical Environment (렉시컬 환경)</strong> : 변수 환경 + 스코프 체인</li>
<li><strong>This Binding</strong> : 컨텍스트에서의 this 값</li>
</ul>
<p>으로 이루어져 있다.</p>
<p>우리는 지금 this binding을 살펴보려고 한다.</p>
<h2 id="그래서-왜-이렇게-동작-하는데">그래서 왜 이렇게 동작 하는데?</h2>
<p>this의 값은 실행 컨텍스트의 this binding 값에 따라 달라지는데 일반적인 함수와 화살표 함수의 동작과정이 다르다.</p>
<p><strong>일반적인 함수</strong>는 호출될 때마다 새로운 실행 컨텍스트를 만들고 실행 컨텍스트 내부의 This Binding은 호출 주체에 따라 결정된다.</p>
<p>화살표 함수가 아니면 대부분 일반 함수로 동작한다.</p>
<p><strong>화살표 함수</strong>는 실행 컨텍스트를 생성할 때 this 바인딩 단계를 생략하고 상위 스코프의 실행 컨텍스트에 존재하는 this를 그대로 <strong>캡처</strong>한다.</p>
<p>만약 전역 함수에서 일반적인 함수와 화살표 함수를 호출한다면 아래와 같이 Call Stack이 그려진다.
<img src="https://velog.velcdn.com/images/lee_areum/post/c9d45af3-e46d-444b-8cbc-7f4218711873/image.png" alt=""></p>
<h3 id="근데-왜-화살표는-다르지"><strong>근데 왜 화살표는 다르지?</strong></h3>
<p>원래 JS는 함수형 언어로 시작했지만 객체 지향적인 기능이 추가되면서 함수가 각 객체의 메서드로 동작할 수 있게 되었다.</p>
<p>그래서 함수를 누가 호출되었는지에 따라 동작을 다르게 해야 했기 때문에 this가 다르게 동작해야 되었다.</p>
<p>화살표 함수는 새로운 this 바인딩을 만들지 않기 때문에 콜백 함수에서의 this 문제를 해결할 수 있었다.</p>
<ul>
<li>일반적인 함수의 콜백 this 문제</li>
</ul>
<pre><code class="language-jsx">// sayName 함수 내부에서 timeout을 줘야 하는 상황
const obj = {
  name: &#39;철수&#39;,
  sayName: function() {
    setTimeout(function() {
      console.log(this.name); // =&gt; 여기서 this는 철수가 아님
    }, 1000);
  }
};

obj.sayName();  // 출력: undefined</code></pre>
<p>이를 해결하기 위해 기존의 JS에서는 임시 변수를 사용해야 했다.</p>
<pre><code class="language-jsx">const obj = {
  name: &#39;철수&#39;,
  sayName: function() {
      let self = this
    setTimeout(function() {
      console.log(self.name);
    }, 1000);
  }
};

obj.sayName();   // 출력: 철수</code></pre>
<p>이 과정은 번거롭기도 하고 코드의 가독성을 떨어뜨렸다.</p>
<p>하지만 화살표가 도입되면서 이러한 문제점이 해결되었다.</p>
<pre><code class="language-jsx">const obj = {
  name: &#39;철수&#39;,
  sayName: function() {
    setTimeout(() =&gt; {
      console.log(this.name);
    }, 1000);
  }
};

obj.sayName();  // 출력: 철수</code></pre>
<p>화살표는 외부 함수의 this를 그대로 사용하기 때문에 sayName 내부의 this는 obj의 this이다.</p>
<p>때문에 setTimeout의 this.name은 철수가 될 수 있었다.</p>
<h2 id="헷갈릴-수-있는-this-예시">헷갈릴 수 있는 this 예시</h2>
<h3 id="메서드-안의-this">메서드 안의 this</h3>
<pre><code class="language-jsx">const person = {
  name: &#39;영희&#39;,
  greet: function() {
    console.log(this.name);
  }
};

person.greet();  // 출력: 영희</code></pre>
<p>이 코드의 Call Stack을 보면</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/3fb42ea1-787c-44c7-9dda-649462009e85/image.png" alt=""></p>
<p>greet가 실행될 때 gloal의 person이 실행했기 때문에</p>
<p>global 실행 Context의 Variable Environment가 참조했던 person 객체를 this로 가지게 된다.</p>
<h3 id="메서드-안에서-내부-함수-호출-시-this">메서드 안에서 내부 함수 호출 시 this</h3>
<pre><code class="language-jsx">const person = {
  name: &#39;영희&#39;,
  greet: function() {
    console.log(this.name); // 영희
    function inner() {
      console.log(this.name);
    }
    inner();
  }
};

person.greet();  // 출력: undefined (또는 전역객체의 name)</code></pre>
<p>greet 함수는 객체를 통해 호출했기 때문에 greet 내부의 this는 person을 바인딩 한다.</p>
<p>하지만 inner 함수는 호출하는 객체가 없었기 때문에 this 를 전역 객체(window) 또는 undefined (strick mode)로 바인딩 한다.</p>
<h3 id="생성자-함수에서의-this">생성자 함수에서의 this</h3>
<pre><code class="language-jsx">function Person(name) {
  this.name = name;
  this.sayName = function() {
    console.log(this.name);
  }
}

const p = new Person(&#39;철수&#39;);
p.sayName();  // 출력: 철수</code></pre>
<p>이 때 sayName은 p가 호출했기 때문에 this binding은 p 인스턴스를 가리킨다.</p>
<h3 id="단독-함수-호출에서의-this">단독 함수 호출에서의 this</h3>
<pre><code class="language-jsx">function showThis() {
  console.log(this);
}

showThis();  // 출력: 전역객체 (브라우저는 window, 엄격모드면 undefined)</code></pre>
<p>이 코드는 그럼 showThis를 호출하는 객체가 없기 때문에 전역객체나 undefined를 호출한다.</p>
<h3 id="이벤트-핸들러에서의-this">이벤트 핸들러에서의 this</h3>
<pre><code class="language-jsx">const button = document.createElement(&#39;button&#39;);
button.textContent = &#39;클릭&#39;;
document.body.appendChild(button);

button.addEventListener(&#39;click&#39;, function() {
  console.log(this);  // 출력: 버튼 DOM 요소
});</code></pre>
<h3 id="클래스-내부-함수에서의-this">클래스 내부 함수에서의 this</h3>
<pre><code class="language-jsx">class User {
  constructor(name) {
    this.name = name;
  }
  printName() {
    console.log(this.name);
  }
}

const user = new User(&#39;지훈&#39;);
user.printName();  // 지훈</code></pre>
<p>다음에 보고 싶은거</p>
<ul>
<li>JS의 비동기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript의 클로저와 실행 컨텍스트]]></title>
            <link>https://velog.io/@lee_areum/JavaScript%EC%9D%98-%ED%81%B4%EB%A1%9C%EC%A0%80%EC%99%80-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@lee_areum/JavaScript%EC%9D%98-%ED%81%B4%EB%A1%9C%EC%A0%80%EC%99%80-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Tue, 08 Apr 2025 08:57:24 GMT</pubDate>
            <description><![CDATA[<h2 id="클로저란-무엇인가">클로저란 무엇인가</h2>
<ul>
<li>외부함수가 종료되어도 클로저 함수는 외부함수의 스코프(함수가 선언된 어휘적 환경)에 접근할 수 있도록 하는 개념</li>
</ul>
<pre><code class="language-jsx">function makeFunc() {
  const name = &quot;Mozilla&quot;;
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();</code></pre>
<p>이 코드를 실행하면 makeFunc이 종료되어도 makeFunc의 내부 변수 name을 조회할 수 있다.</p>
<h2 id="어떻게-가능한가">어떻게 가능한가?</h2>
<ul>
<li>실행 컨텍스트가 외부 함수에 대한 렉시컬 환경에 대한 참조값을 가지고 있어서 상위 스코프에 접근할 수 있다.</li>
</ul>
<p><a href="https://velog.velcdn.com/images/lee_areum/post/7863eac0-b0bf-49ab-9c83-e02d3ae3914d/image.png"></a></p>
<h3 id="이를-이해하기-위한-개념들">이를 이해하기 위한 개념들</h3>
<ul>
<li><p>스코프</p>
<ul>
<li>선언된 변수에 대해 접근 가능한 유효범위!</li>
<li>하위 스코프는 상위 스코프에 접근 가능하지만 반대는 불가능</li>
</ul>
</li>
<li><p>정적 스코프와 동적 스코프</p>
<ul>
<li><p>정적 스코프(렉시컬 스코프) : 스코프가 컴파일 타임에 결정된다.</p>
<pre><code class="language-jsx">  var name = &#39;Tom&#39;

  function myName() {
    var name = &#39;Janet&#39;;
    getName();
  }

  function getName() {
    console.log(name);
  }

  myName(); // Tom</code></pre>
</li>
<li><p>동적 스코프 : 런타임시에 스코프가 결정</p>
<pre><code class="language-jsx">  var name = &#39;Tom&#39;

  function myName() {
    var name = &#39;Janet&#39;;
    getName();
  }

  function getName() {
    console.log(name);
  }

  myName(); // Janet</code></pre>
</li>
<li><p>JS는 정적 스코프 방식을 택한다.</p>
</li>
</ul>
</li>
<li><p>스코프 체인</p>
<p>  현재 스코프 레벨에서 참조값이 없는 경우 상위 레벨의 스코프에서 참조값을 찾아 나가는 현상</p>
<p>  스코프를 안쪽에서 바깥쪽으로 단계적으로 탐색하는 과정이다.</p>
</li>
<li><p>실행 컨텍스트 : 실행할 코드에 제공할 환경 정보들을 모아놓은 객체</p>
</li>
</ul>
<p>실행 컨텍스트는 복잡한 개념이라 자세히 설명해 보겠다.</p>
<h3 id="실행-컨텍스트execution-context">실행 컨텍스트<strong>(Execution Context)</strong></h3>
<p>실행할 코드에 제공할 환경 정보들을 모아놓은 객체</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/c7cdb50e-f6b9-4956-932f-f04e3e6d5e41/image.png" alt=""></p>
<p>JS 엔진의 Call Stack에 담는 단위이다</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/a2369c81-32c0-48e2-8489-dc4c6edf69b9/image.png" alt=""></p>
<p>처음 프로그램을 실행하면 전역 컨텍스트(Global Context)가 콜스택에 담긴다.</p>
<ul>
<li>변수 객체, 스코프 체인, this 값에 대한 정보가 담겨 있음</li>
</ul>
<h3 id="실행-컨텍스트-내부-구조">실행 컨텍스트 내부 구조</h3>
<ul>
<li>Variable Environment (변수 환경) : 초기화 시점의 변수, 함수 선언 정보 저장<ul>
<li>Environment Record (번수 저장소) : 실제 식별자와 그 값을 저장하는 공간</li>
<li>Outer Lexical Environment (스코프 체인) : 상위 스코프(외부 렉시컬 환경)를 참조하여 스코프 체인을 만듬</li>
</ul>
</li>
<li>Lexical Environment (렉시컬 환경) : 변수 환경 + 스코프 체인</li>
<li>This Binding : 컨텍스트에서의 this 값</li>
</ul>
<p>으로 이루어져 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/385dbf1a-c4cb-498a-a77d-bbd3d073f34d/image.png" alt=""></p>
<ul>
<li>Outer Lexical Environment 은 상위 스코프의 Lexical Environment를 참조한다.</li>
<li>때문에 현재 스코프에 없는 값이라도 Outer를 타고 올라가서 상위 스코프에 있는 값을 조회할 수 있다.</li>
</ul>
<pre><code class="language-jsx">function outer() {
  let a = 1;

  function inner() {
    console.log(a); // 여기서 a는 어디서 찾을까?
  }

  inner();
}</code></pre>
<p>해당 예시에서도 스코프 체인이 아래와 같이 연결되어 있기 때문에 inner에서 a를 찾을 수 있는 것이다.</p>
<pre><code class="language-jsx">innerContext.LexicalEnvironment
   └── outerContext.LexicalEnvironment
         └── globalContext.LexicalEnvironment</code></pre>
<h3 id="️조금-깊이-들어가-볼까️">⁉️조금 깊이 들어가 볼까⁉️</h3>
<p>ES6 이전에는 variable object / Scope chain / thisValue 로 표현했지만 최신 표준(ES6+)에서는 위와 같의 정의한다. (더 세분화)</p>
<p>ES5에서는  Variable Environment는 var, let, const, function 모두 저장했다.</p>
<p>ES6부터  <code>LexicalEnvironment</code> 에는  <code>let</code>, <code>const</code>, <code>function</code> 을 저장하고</p>
<p>Variable Environment에는 var 변수를 저장한다</p>
<p>프로그램 실행 초기에는 VariableEnvironment와 LexicalEnvironment가 <strong>같은 참조(=객체)를 가리킨다.</strong></p>
<p>이후에 let/const가 보이면 새로운 Record가 생성될 수 있다. (var와 let/const는 선언 시기가 다르다)</p>
<table>
<thead>
<tr>
<th>시점</th>
<th>VE와 LE 관계</th>
<th>var</th>
<th>let/const/function</th>
</tr>
</thead>
<tbody><tr>
<td>실행 컨텍스트 생성 초기</td>
<td>같은 객체를 참조함</td>
<td>✅ VE에 저장됨</td>
<td>❌ 아직 없음</td>
</tr>
<tr>
<td>let/const/function 선언 시</td>
<td>LE에만 추가됨</td>
<td>(VE에 이미 있음)</td>
<td>✅ LE에만 저장됨</td>
</tr>
<tr>
<td>실행 단계 이후</td>
<td>둘은 구조상 따로 관리됨 (같은 객체였어도!)</td>
<td><code>var</code> 있음</td>
<td><code>let</code>, <code>const</code> 없음</td>
</tr>
</tbody></table>
<p>변수 검색 시 Lexical Environment에서만 탐색한다.</p>
<h2 id="그래서-클로저에-대해-다시-설명하자면">그래서 클로저에 대해 다시 설명하자면</h2>
<p>실행 컨텍스트는 함수가 실행이 종료되면 사라진다.</p>
<p>하지만, 클로저란 <strong>함수가 선언될 당시의 Lexical Environment를 기억해서</strong></p>
<p>그 환경에 있는 변수들에 <strong>함수가 실행된 이후에도 접근할 수 있게 하는 기능</strong></p>
<p>→ &quot;렉시컬 환경이 GC(Garbage Collection) 대상이 되지 않고 살아남기 때문에&quot; 가능한 기능이다.</p>
<pre><code class="language-jsx">function outer() {
  let count = 0;

  return function inner() {
    count++;
    console.log(count);
  }
}

const fn = outer();  // 여기서 inner 함수가 반환됨
fn(); // 1
fn(); // 2
</code></pre>
<h3 id="원래라면">원래라면:</h3>
<ul>
<li><code>outer()</code> 실행이 끝나면, 그 안에서 만든 <code>count</code> 변수는 메모리에서 사라져야 함</li>
</ul>
<h3 id="그런데-실제로는">그런데 실제로는:</h3>
<ul>
<li><code>inner()</code> 함수가 <code>count</code>에 접근하니까</li>
<li>JS 엔진은 <code>outer</code>의 LexicalEnvironment를 <strong>메모리에서 제거하지 않음</strong>
➝ 즉, <strong><code>count</code>가 살아있는 상태로 유지됨</strong></li>
</ul>
<h3 id="실행-컨텍스트로-보는-동작-원리">실행 컨텍스트로 보는 동작 원리</h3>
<pre><code class="language-jsx">var food = &#39;🍕&#39;;

function outer() {
  var food = &#39;🍔&#39;;

  function inner() {
    console.log(&#39;I like&#39;, food);
  }

  return inner;
}

var myFunc = outer(); // inner 함수 리턴받음
myFunc();             // 호출은 전역에서!</code></pre>
<h3 id="🧭-흐름-설명">🧭 흐름 설명</h3>
<table>
<thead>
<tr>
<th>순서</th>
<th>설명</th>
<th>실행 컨텍스트 스택 상태</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>프로그램 시작</td>
<td><code>[Global]</code></td>
</tr>
<tr>
<td>2</td>
<td><code>outer()</code> 호출</td>
<td><code>[outer, Global]</code></td>
</tr>
<tr>
<td>3</td>
<td><code>outer()</code> 내부 실행 완료 → <code>inner</code> 리턴</td>
<td><code>[Global]</code></td>
</tr>
<tr>
<td>4</td>
<td><code>myFunc()</code> 호출 (<code>inner()</code> 실행)</td>
<td><code>[inner, Global]</code></td>
</tr>
<tr>
<td>5</td>
<td><code>console.log(...)</code> 실행</td>
<td>콘솔에 <code>&quot;I like 🍔&quot;</code></td>
</tr>
<tr>
<td>6</td>
<td><code>inner()</code> 종료</td>
<td><code>[Global]</code></td>
</tr>
<tr>
<td>7</td>
<td>종료</td>
<td><code>[Global]</code> 해제됨</td>
</tr>
</tbody></table>
<p>outer가 종료되었지만, inner에서 outer를 참조하고 있기 때문에 outer의 실행 컨텍스트는 사라지지 않는다.</p>
<p>크롬에서 해당 코드를 디버깅 해보면</p>
<p>실제 스코프를 볼 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/f87f0c22-9271-4834-ba67-ee43b5500e52/image.png" alt=""></p>
<p>outer는 스코프 체인이 local - global 이지만
<img src="https://velog.velcdn.com/images/lee_areum/post/fb8e13d4-76d0-4239-9e1a-46898c4c112a/image.png" alt=""></p>
<p>inner는 스코프 체인이 local - outer - global 이다.</p>
<h2 id="활용방안">활용방안</h2>
<ul>
<li><p>함수 팩토리</p>
<pre><code class="language-jsx">  function makeAdder(x) {
    return function (y) {
      return x + y;
    };
  }

  const add5 = makeAdder(5);
  const add10 = makeAdder(10);

  console.log(add5(2)); // 7
  console.log(add10(2)); // 12</code></pre>
<p>  makeAdder는 함수를 만들어 내는 팩토리로 각각 5, 10을 더하는 함수를 만들수 있다.</p>
<p>  여기서 클로저는 add5와 add10으로 같은 로직을 공유하지만 서로 다른 환경을 저장한다.</p>
</li>
<li><p>Private 변수 구현</p>
<p>  메서드를 비공개로 선언 / 내부의 다른 메서드만 그 메서드를 호출하도록 함.</p>
<pre><code class="language-jsx">  const counter = (function () {
    let privateCounter = 0;
    function changeBy(val) {
      privateCounter += val;
    }

    return {
      increment() {
        changeBy(1);
      },

      decrement() {
        changeBy(-1);
      },

      value() {
        return privateCounter;
      },
    };
  })();

  console.log(counter.value()); // 0.

  counter.increment();
  counter.increment();
  console.log(counter.value()); // 2.

  counter.decrement();
  console.log(counter.value()); // 1.</code></pre>
<p>  이렇게 코드를 구성하면 외부에서 privateCouter 변수와 changeBy 함수에 접근 할 수 없지만</p>
<p>  반환된 increment, decrement, value 함수를 통해 값의 증가, 감소, 조회 기능을 실행할 수 있습니다.</p>
<p>  만약 여러개의 카운터를 생성한다 하더라도</p>
<pre><code class="language-jsx">  const makeCounter = function () {
    let privateCounter = 0;
    function changeBy(val) {
      privateCounter += val;
    }
    return {
      increment() {
        changeBy(1);
      },

      decrement() {
        changeBy(-1);
      },

      value() {
        return privateCounter;
      },
    };
  };

  const counter1 = makeCounter();
  const counter2 = makeCounter();

  console.log(counter1.value()); // 0.

  counter1.increment();
  counter1.increment();
  console.log(counter1.value()); // 2.

  counter1.decrement();
  console.log(counter1.value()); // 1.
  console.log(counter2.value()); // 0.</code></pre>
<p>  각각의 클로저는 독립적인 환경을 조성하며, 서로 영향을 미치지 않습니다.</p>
</li>
</ul>
<h2 id="장단점">장단점</h2>
<h3 id="클로저의-장점">클로저의 장점</h3>
<ol>
<li>전역변수 사용의 최소화 / 의도하지 않은 전역변수 값 변경 예방</li>
<li>데이터 보존 가능</li>
<li>모듈화를 통한 코드 재사용에 편리</li>
</ol>
<pre><code class="language-jsx">// myModule.js
let x = 5;
export const getX = () =&gt; x;
export const setX = (val) =&gt; {
  x = val;
};</code></pre>
<pre><code class="language-jsx">import { getX, setX } from &quot;./myModule.js&quot;;

console.log(getX()); // 5
setX(6);
console.log(getX()); // 6</code></pre>
<ol>
<li><p>정보의 접근 제한(캡슐화)</p>
<pre><code class="language-jsx"> function outer() {
   let getY;
   {
     const y = 6;
     getY = () =&gt; y;
   }
   console.log(typeof y); // undefined
   console.log(getY()); // 6
 }

 outer();</code></pre>
</li>
</ol>
<h3 id="클로저-사용시-주의할점">클로저 사용시 주의할점</h3>
<ul>
<li>메모리 사용의 주의<ul>
<li>클로저를 사용하면 외부함수의 생명주기가 끝났음에도 가비지 콜렉터에 의해 메모리가 해제되지 않음.</li>
</ul>
</li>
</ul>
<p>→ 클로저를 할당한 변수에 null을 할당하여 메모리를 해제할 수 있음.</p>
<h3 id="참고">참고</h3>
<ul>
<li><a href="https://velog.io/@minh0518/%EB%A9%B4%EC%A0%91%EA%B4%80-%EC%95%9E%EC%97%90%EC%84%9C-%ED%81%B4%EB%A1%9C%EC%A0%80-closure%EC%9D%98-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC%EB%A5%BC-%EB%A7%90%ED%95%B4%EB%B3%B4%EC%9E%90">https://velog.io/@minh0518/면접관-앞에서-클로저-closure의-동작원리를-말해보자</a></li>
<li><a href="https://gamguma.dev/post/2022/04/js_execution_context">https://gamguma.dev/post/2022/04/js_execution_context</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript의 엔진이란]]></title>
            <link>https://velog.io/@lee_areum/JavaScript%EC%9D%98-%EC%97%94%EC%A7%84%EA%B3%BC-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@lee_areum/JavaScript%EC%9D%98-%EC%97%94%EC%A7%84%EA%B3%BC-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Sun, 16 Feb 2025 04:53:23 GMT</pubDate>
            <description><![CDATA[<h2 id="js의-엔진">JS의 엔진</h2>
<p>JavaScript 엔진이란 JavaScript를 실행하는 프로그램 또는 인터프리터</p>
<h3 id="주요-엔진-종류">주요 엔진 종류</h3>
<ul>
<li><p>V8(Chrome, Node.js)
  구글에서 개발한 오픈소스 엔진
  C++로 개발된 빠른 실행속도와 높은 성능을 가진 엔진
<em>-&gt; 속도향상을 위해 인라인 캐싱 등 최적화 기법을 사용</em> 
  주로 Chrome 브라우저나 Node.js 런타임 환경에서 사용
  안드로이드 브라우저에도 탑재되어있음</p>
<ul>
<li><p>SpiderMonkey(FireFox)
Mozilla에서 개발한 엔진
최초의 JS엔진으로 안정성과 호환성에 중점을 둔 엔진
주로 Firefox 브라우저에서 사용</p>
</li>
<li><p>JavaScriptCore(Safari)
Apple에서 개발한 엔진, MacOS 및 IOS 환경의 Safari 브라우저에서 사용</p>
</li>
</ul>
<p>그외에도 Chakra(Microsoft), Hermes(React Native) 등이 있다.</p>
<h3 id="javascript-엔진의-주요-구성-요소">JavaScript 엔진의 주요 구성 요소</h3>
<h3 id=""></h3>
</li>
<li><p>JS 엔진은 Memory Heap과 Call Stack으로 구성된다.
<img src="https://velog.velcdn.com/images/lee_areum/post/5b8989b9-df7f-4767-ac0c-a980ff18d3e6/image.png" alt=""></p>
<h4 id="메모리-힙memory-heap">메모리 힙(Memory Heap)</h4>
<ul>
<li>메모리 할당이 발생하는 위치</li>
<li>동적으로 생성되는 데이터를 저장하는 메모리 공간임</li>
</ul>
<h4 id="콜-스택call-stack">콜 스택(Call Stack)</h4>
<ul>
<li>코드가 실행될 때 스택 프레임(프로그램이 어느 위치에 있는가)를 기록하는 데이터 구조</li>
<li>스택 형태로 동작하고 함수가 호출될 때 스택에 추가되고 실행 종료 시 스택에서 제거</li>
<li><strong>FILO</strong>(first in Last out) 구조</li>
<li>Call Stack에서 실행하는 프로그램 단위를 스택 프레임 이라고 한다.</li>
</ul>
<h3 id="런타임">런타임</h3>
<p>JS 런타임 환경은 JS 실행 외에도 추가적인 기능들(api)을 사용한다.
DOM, AJAX, setTimeout 등도 엔진에 포함되지 않은 기능들이다.</p>
<p>여기서 나오는게 이벤트 루프(Event Loop)이다.</p>
<h4 id="이벤트-루프event-loop">이벤트 루프(Event Loop)</h4>
<p>Event Loop는 JS 엔진과 런타임 환경의 중간 역할로
싱글 스레드인 JS 엔진을 보조하여 비동기 작업을 처리하는 역할을 한다.</p>
<p>이벤트 루프는 비동기 작업(네트워크 요청, 사용자 이벤트 등)이 완료될 때까지 기다렸다가 완료되면 해당 작업의 콜백 함수를 콜백 큐에 추가한다.
<img src="https://velog.velcdn.com/images/lee_areum/post/c7cdb50e-f6b9-4956-932f-f04e3e6d5e41/image.png" alt=""></p>
</li>
<li><ul>
<li>콜백큐 **
비동기 작업의 결과나 나중에 실행되어야 하는 작업들이 대기하는 공간 <strong>FIFO</strong>(first in first out) 구조</li>
</ul>
</li>
</ul>
<br>

<p><em>콜백 큐에는 또 세가지 종류가 있는데</em></p>
<ul>
<li><p><strong>테스크 큐(Task Queue)</strong> : 일반적으로 매크로 태스크(Macrotask Queue)라고도 불림,
setTimeout, setInterval 등의 비동기 작업</p>
</li>
<li><p><strong>마이크로태스크 큐(Microtask Queue)</strong>: 프로미스(Promise)의 콜백 함수나 async / await</p>
</li>
<li><p><strong>애니메이션 프레임(Animation Frames)</strong>: 브라우저 환경에서 화면을 업데이트하는 작업, ex) requestAnimationFrames</p>
<p>마이크로테스크 큐 &gt; 애니메이션 프레임 &gt; 테스크 큐 순으로 우선순위를 가지고 있음.</p>
<p>이런 우선순위를 실행하는 작업을 이벤트 루프가 처리한다.</p>
</li>
</ul>
<br>

<h3 id="이벤트-루프event-loop의-동작-과정">이벤트 루프(Event Loop)의 동작 과정</h3>
<p> 이벤트 루프는 콜 스택과 콜백 큐를 지속적으로 확인하며, 콜 스택이 비어있으면 콜백 큐에서 가장 오래된 작업(FIFO)을 꺼내서 콜 스택으로 옮긴다.</p>
<p>이미지와 함께 보도록 하자.</p>
<ol>
<li><strong>콜 스택(Call Stack) 확인</strong>: 먼저 현재 콜 스택이 비어 있는지 확인하고
만약 콜 스택에 아직 처리되지 않은 함수가 있다면, 해당 함수가 완전히 실행될 때까지 대기한다.
<img src="https://velog.velcdn.com/images/lee_areum/post/689cf568-1c66-40eb-8dda-bfd87269f99d/image.png" alt=""></li>
<li><strong>콜백 큐(Callback Queue) 확인</strong>: 만약 콜 스택이 비어 있다면, 콜백 큐를 확인한다.
<em>콜백 큐에는 웹 API 등에서 생성된 콜백 함수들이 대기한다.</em>
<img src="https://velog.velcdn.com/images/lee_areum/post/e56dd277-5ce8-4d13-8602-4413e595fa6e/image.png" alt=""></li>
<li><strong>함수 이동</strong>: 콜백 큐에서 가장 오래된 함수를 꺼내서 콜 스택으로 옮긴다.
<img src="https://velog.velcdn.com/images/lee_areum/post/50768979-8426-49c0-b704-154046515863/image.png" alt=""></li>
<li><strong>함수 실행</strong>: 해당 함수가 콜 스택에서 실행되고 실행이 끝나면 콜 스택에서 빠져나간다.
위 과정들을 프로그램이 종료될 때까지 반복한다.</li>
</ol>
<br>

<h3 id="예시">예시</h3>
<p>이제 여러 예시 코드들에 따른 JS엔진의 동작과정을 살펴보겠다.</p>
<pre><code>function greet() {
  return &#39;Hello!&#39;;
}

function respond() {
  return setTimeout(() =&gt; {
    return &#39;Hey!&#39;;
  }, 1000);
}

greet();
respond();</code></pre><ol>
<li>먼저 great() 함수를 호출하고(콜 스택에 넣고 실행한다.)
다음으로 respond() 함수를 호출한다. </li>
<li>setTimeout 함수와 respond 함수가 콜 스택에서 빠져나오면서 값을 반환하고
setTimeout에 전달한 콜백 함수만 빠져나와 웹 api로 전달된다.
웹 api에서는 setTimeout 함수의 두 번째 인수였던 1초 만큼 실행된다.<ol start="3">
<li>1초가 지나면 콜백 큐(Task Queue)로 돌아간다.</li>
<li>이벤트 루프가 콜 스택이 비어있는지 확인하고 콜백 큐에 있는 콜백 함수를 콜 스택에 추가한다.</li>
<li>콜백 함수는 콜 스택에 추가되고, 호출된 후 갑슬 반환하여 콜 스택에서 빠져나가게 된다.<br>

</li>
</ol>
</li>
</ol>
<p>관련 예시는 아래 블로그에 잘 기입되어 있다.
<a href="https://yong-nyong.tistory.com/71">https://yong-nyong.tistory.com/71</a></p>
<p>예시를 보면서 async await는 예상과 다른 순서로 진행되었다.
async 함수 내에서 await를 만나기 전까지는 코드가 순차적으로 실행되지만
<img src="https://velog.velcdn.com/images/lee_areum/post/34ea8691-639b-4ad3-9ec7-b8d4be78f5ca/image.png" alt="">
await 함수를 만나는 순간 await 함수 내 동작(Promise 객체 반환)을 실행하고 async 함수는 일시정지되서 마이크로 테스크 큐로 이동된다.</p>
<h4 id="참고">참고</h4>
<ul>
<li><a href="https://medium.com/sessionstack-blog/how-does-javascript-actually-work-part-1-b0bacc073cf">https://medium.com/sessionstack-blog/how-does-javascript-actually-work-part-1-b0bacc073cf</a></li>
<li><a href="https://medium.com/sessionstack-blog/how-javascript-works-inside-the-v8-engine-5-tips-on-how-to-write-optimized-code-ac089e62b12e">https://medium.com/sessionstack-blog/how-javascript-works-inside-the-v8-engine-5-tips-on-how-to-write-optimized-code-ac089e62b12e</a><ul>
<li>출처 : <a href="https://yong-nyong.tistory.com/71">https://yong-nyong.tistory.com/71</a> [💻용뇽 개발 노트💻:티스토리]</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript의 구조 분해]]></title>
            <link>https://velog.io/@lee_areum/JavaScript%EC%9D%98-%EA%B5%AC%EC%A1%B0-%EB%B6%84%ED%95%B4</link>
            <guid>https://velog.io/@lee_areum/JavaScript%EC%9D%98-%EA%B5%AC%EC%A1%B0-%EB%B6%84%ED%95%B4</guid>
            <pubDate>Sat, 11 Jan 2025 05:00:46 GMT</pubDate>
            <description><![CDATA[<h3 id="구조-분해-할당이란">구조 분해 할당이란?</h3>
<p>배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JS의 표현식</p>
<h4 id="ex">ex)</h4>
<pre><code>var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20

// Stage 4(finished) proposal
({ a, b, ...rest } = { a: 10, b: 20, c: 30, d: 40 });
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}</code></pre><p><img src="https://velog.velcdn.com/images/lee_areum/post/a721c335-dbb1-476e-85ac-a9891f00e83a/image.png" alt=""></p>
<p>구조 분해 할당은 Perl이나 Python 같은 다른 언어도 가지고 있는 기능이다.</p>
<pre><code>var x = [1, 2, 3, 4, 5];
var [y, z] = x;
console.log(y); // 1
console.log(z); // 2</code></pre><p>나머지 연산자를 사용하지 않으면 값을 앞에서 부터 가져온다.</p>
<br>

<p>선언부에서 값 할당을 분리해도 구조 분해가 가능하다.</p>
<pre><code>var a, b;

[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2</code></pre><br>

<p>기본값을 할당할 경우 분해한 값이 undefined일 때 기본값을 사용한다.</p>
<pre><code>var a, b;

[a = 5, b = 7] = [1];
console.log(a); // 1
console.log(b); // 7</code></pre><br>

<h3 id="분해할당-활용처">분해할당 활용처</h3>
<p>원래 값을 교환하려면 임시 변수가 필요하다
하지만 분해할당을 사용하면 임시 변수 없이 두 변수의 값을 교환할 수 있다.</p>
<pre><code>var a = 1;
var b = 3;

[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1</code></pre><h3 id="변수에-배열의-나머지-값-할당하기">변수에 배열의 나머지 값 할당하기</h3>
<p>...(나머지 구문)를 사용하면 구문을 분해하고 
남은 부분을 하나의 변수에 할당할 수 있음.</p>
<pre><code>var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]</code></pre><p>이 때 나머지 구문은 항상 마지막에 와야함.
아닐 경우 syntaxError가 발생함</p>
<h2 id="객체-구조-분해">객체 구조 분해</h2>
<pre><code>var o = { p: 42, q: true };
var { p, q } = o;

console.log(p); // 42
console.log(q); // true</code></pre><pre><code>var o = { p: 42, q: true , f: false, k:30};
var { p: foo, q: bar, ...g } = o;

console.log(foo); // 42
console.log(bar); // true
console.log(g); // { f: false, k: 30 }</code></pre><p>객체 구조 분해도 선언과 할당을 분리할 수 있다.</p>
<pre><code>var a, b;

({ a, b } = { a: 1, b: 2 });</code></pre><h4 id="새로운-변수-이름으로-할당하기">새로운 변수 이름으로 할당하기</h4>
<p>기존에 할당된 이름 대신 새로운 변수명을 할당시킬 수 있다.</p>
<pre><code>var o = { p: 42, q: true };
var { p: foo, q: bar } = o;

console.log(foo); // 42
console.log(bar); // true</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[프론트 이벤트 버블링에 관하여]]></title>
            <link>https://velog.io/@lee_areum/%ED%94%84%EB%A1%A0%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC</link>
            <guid>https://velog.io/@lee_areum/%ED%94%84%EB%A1%A0%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC</guid>
            <pubDate>Thu, 12 Dec 2024 03:57:03 GMT</pubDate>
            <description><![CDATA[<p>아래 코드에서 우리는 em부분을 클릭해도 
div에 할당된 핸들러가 동작한다.
이것은 어떻게 가능한 것인가?</p>
<pre><code>&lt;div onclick=&quot;alert(&#39;div에 할당한 핸들러!&#39;)&quot;&gt;
  &lt;em&gt;
     &lt;code&gt;EM&lt;/code&gt;을 클릭했는데도      &lt;code&gt;DIV&lt;/code&gt;에 할당한 핸들러가 동작합니다.
&lt;/em&gt;
&lt;/div&gt;</code></pre><p>바로 버블링이 발생하기 때문이다</p>
<h3 id="버블링">버블링</h3>
<p>버블링이랑
특정 화면 요소에서 이벤트가 발생했을 때
이벤트가 더 상위의 화면 요소들로 전달되어가는 것이다.</p>
<p>마치 vue에서 emit을 통해 부모 컴포넌트로 이벤트를 발생시키는 것과 비슷한 개념 같다.</p>
<p>한 요소에서 이벤트가 발생하면
이 요소의 이벤트 핸들러가 동작하고 부모의 핸들러가 동작한다.
이 과정을 최상위 요소를 만날 때까지 반복한다.</p>
<pre><code>&lt;div onClick=&quot;alert(&quot;div&quot;)&quot;&gt;
  부모요소
    &lt;p onClick=&quot;alert(&quot;p&quot;)&quot;&gt;자식 요소&lt;/p&gt;
&lt;/div&gt;</code></pre><p>이런 구조에서 p를 클릭한다면
p의 핸들러를 동작하고 부모인 div의 핸들러를 동작하게 된다.</p>
<p>따라서 p alert가 동작하고 div alert 가 동작하는 것이다.</p>
<p>이러한 일련의 동작을 이벤트의 버블링이라고 한다.</p>
<ul>
<li>거의 모든 이벤트는 버블링이 작동하지만
focus와 같은 일부 이벤트는 버블링이 작동하지 않는다.</li>
</ul>
<h2 id="그럼-어디서-이벤트가-일어났는지는-어떻게-알-수-있는가">그럼 어디서 이벤트가 일어났는지는 어떻게 알 수 있는가?</h2>
<p>이벤트 핸들러의 파라미터로 들어오는
event 객체를 통해 알 수 있다.</p>
<pre><code>form.onclick = function(event) {
 console.log(&#39;target : &#39;+event.target.tagName)
 console.log(&#39;this : &#39; + this.tagName)
};</code></pre><p>이벤트 핸들러 내에서는  this라는 요소와
event라는 요소를 사용할 수 있다.</p>
<p>this는 이벤트 핸들러가 존재하는 부모 요소를 가리키고
event.target은 이벤트가 최초 발생한 자식 요소를 가리킨다.</p>
<pre><code>&lt;form onClick = ...&gt;
  &lt;div&gt;
    &lt;p&gt;&lt;/p&gt;
  &lt;/div&gt;
&lt;/form&gt;</code></pre><p>이런 구조일 때 위의 이벤트를 form 에 적용했다고 가정해보자
이 상황에서 p를 클릭하면</p>
<pre><code>target : p
this : form</code></pre><p>으로 결과값이 발생합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 변수 호이스팅이란?]]></title>
            <link>https://velog.io/@lee_areum/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%B3%80%EC%88%98-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@lee_areum/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%B3%80%EC%88%98-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Mon, 25 Nov 2024 13:09:32 GMT</pubDate>
            <description><![CDATA[<h3 id="호이스팅">호이스팅</h3>
<p>인터프리터가 코드를 실행하기 전에 함수, 변수, 클래스 또는 import의 선언문을 해당 범위의 맨 위로 끌어올리는 것처럼 보이는 현상</p>
<h4 id="var-변수-호이스팅">var 변수 호이스팅</h4>
<p>아래 javascript 코드를 vs에서 실행하면</p>
<pre><code>console.log(a)
var a = 10
console.log(a)</code></pre><p>원래라면 a는 참조오류가 나야한다.
하지만 </p>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/571997b1-6469-469d-ad6f-4a2d55c9e3de/image.png" alt=""></p>
<p>결과로 나온다.</p>
<p>왜? 그럴까?</p>
<p>javascript가 해당 코드를 실행할 때 변수 호이스팅이 발생하여
변수 선언문을 최상단으로 보낸다.</p>
<pre><code>var a
a = undefined
console.log(a)
a = 10
console.log(a)</code></pre><p>결과적으로 이렇게 변환해서 실행하기 때문에 오류가 나지 않고 undefined가
나타나는 것이다.</p>
<h4 id="let-변수-호이스팅">let 변수 호이스팅</h4>
<p>여기서 var가 아니라 ES6부터 등장한 let으로 선언하면 어떻게 동작할까?</p>
<p>정답은 &#39;실행환경에 따라 다르다.&#39; 이다.</p>
<p>크롬에서는
<img src="https://velog.velcdn.com/images/lee_areum/post/a9568bfd-db59-4a3f-9ba1-baca5756aea6/image.png" alt="">
이렇게 오류가 난다.</p>
<p>vs 코드에서도 오류가 난다.</p>
<p><em>personal-JS에서는 정상 동작함</em></p>
<blockquote>
<p>JavaScript는 왜 이따위? 일까</p>
</blockquote>
<p> 초기의 Javascript는 html 웹 사이트의 동적인 동작을 도와주는 작은 영역이었다.
동적인 영역의 중요성이 커지면서 js의 역할이 커져갔고 js가 발전함에 따라 이전에 버그로 생각했던 코드들이 레거시로 남아있게 된 것</p>
<h4 id="const-상수의-호이스팅">const 상수의 호이스팅</h4>
<p>그럼 상수 const는 어떻게 동작할까?</p>
<pre><code>console.log(PI)
const PI = 3.141592
console.log(PI)</code></pre><p>결과는 
personal-JS에서는 const도 호이스팅 되어</p>
<pre><code>undefined
3.141592</code></pre><p>로 나오는 것을 볼 수 있다.
_ 하지만 크롬과 vs에서는 오류가 난다. _</p>
<p>_ let과 const의 호이스팅은 personal-JS의 오류 같기도하다.._</p>
<h4 id="호이스팅의-4가지-특징">호이스팅의 4가지 특징</h4>
<ol>
<li><p>변수를 선언하기 전에 값을 미리 사용할 수 있는 것처럼 보임</p>
<pre><code>console.log(myVar); // undefined
var myVar = 10;
console.log(myVar); // 10</code></pre></li>
<li><p>변수 선언 전에 참조할 수는 있지만(var) 값은 무조건 undefined</p>
<pre><code>console.log(myVar); // undefined
var myVar;
myVar = 10;
console.log(myVar); // 10</code></pre></li>
<li><p>변수가 선언되면, 그 변수는 코드의 선언된 줄 이전부터 영향을 미칠 수 있어</p>
<pre><code>console.log(myVar); // undefined
var myVar = 10;
</code></pre></li>
</ol>
<p>if (true) {
  console.log(myVar); // undefined
  var myVar = 20;
  console.log(myVar); // 20
}</p>
<p>console.log(myVar); // 10</p>
<pre><code>
4. 변수를 선언하면 전 코드에도 영향을 미친다.
ex) 선언된 변수 이름이 이전과 동일하면 이전 코드를 가릴 수 있음
</code></pre><p>const x = 1;
{
  console.log(x); // 참조 에러
  const x = 2;
}</p>
<p>```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[23.08.29 오늘의 끄적]]></title>
            <link>https://velog.io/@lee_areum/23.08.29-%EC%98%A4%EB%8A%98%EC%9D%98-%EB%81%84%EC%A0%81</link>
            <guid>https://velog.io/@lee_areum/23.08.29-%EC%98%A4%EB%8A%98%EC%9D%98-%EB%81%84%EC%A0%81</guid>
            <pubDate>Tue, 29 Aug 2023 14:28:42 GMT</pubDate>
            <description><![CDATA[<h1 id="용어-정리">용어 정리</h1>
<h2 id="msa">MSA</h2>
<p>작은 독립적인 서비스를 연결한 구조</p>
<p>Gateway에서 API 링크를 보고 업무별로 분리하여 전송/처리</p>
<h2 id="interface-통신">Interface 통신</h2>
<ul>
<li>MCI
같은 구조를 가진 프로그램끼리 통신
ex) java - java</li>
<li>EAI
다른 구조를 가진 프로그램끼리 통신
ex) java-c / xml-c</li>
<li>FEP
내부망과 외부망의 통신
ex) 파일 통신</li>
</ul>
<h2 id="전문-통신">전문 통신</h2>
<p>고정된 길이의 서로 약속한 형식(자료형, 길이)을 주고 받는 통신</p>
<ul>
<li>Lengthed 전문
한글도 1개의 문자로 취급하는 전문</li>
<li>fixed Lengthed 전문
1byte를 기준으로 하는 전문</li>
<li>delimiter 전문
구분자를 사용하는 전문</li>
</ul>
<p>** API 통신 **
전문통신으로 불가능한 자유로운 형식의 통신</p>
<p>ex) xml, json</p>
<h2 id="도커컨테이너">도커&amp;컨테이너</h2>
<ul>
<li>도커 : 컨테이너를 실행시키는 도구 중 가장 유명한 도구
컨테이너를 내려받거나 공유함</li>
<li>컨테이너 : 어플을 환경까지 감싸서 어디서든 실행할 수 있도록 해주는 기술</li>
<li>쿠버네티스 : 분산 관리 서비스
컨테이너 분산배치, 상태관리, 구동환경 관리도구
컨테이너를 만들고</li>
</ul>
<h2 id="명명규칙-fe">명명규칙 (FE)</h2>
<p>M : main</p>
<p>T : Tab</p>
<p>L : Layer</p>
<p>P : Popup</p>
<p>C : Component</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CleanCode] 1장 깨끗한 코드]]></title>
            <link>https://velog.io/@lee_areum/CleanCode-1%EC%9E%A5-%EA%B9%A8%EB%81%97%ED%95%9C-%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@lee_areum/CleanCode-1%EC%9E%A5-%EA%B9%A8%EB%81%97%ED%95%9C-%EC%BD%94%EB%93%9C</guid>
            <pubDate>Wed, 08 Mar 2023 13:01:32 GMT</pubDate>
            <description><![CDATA[<p>나쁜 코드는 일의 생산성을 떨어뜨린다</p>
<p>시간이 촉박하다고 나쁜 코드를 양산하더라도 결국에는 나쁜 코드가 발목을 잡는다</p>
<p>기한을 맞추는 유일한 방법은 좋은 코드를 작성하는 습관을 들이는 것이다.</p>
<br>



<h1 id="프로그래머들이-말하는-깨끗한-코드">프로그래머들이 말하는 깨끗한 코드</h1>
<br>



<h3 id="비야네-스트롭스트룹">비야네 스트롭스트룹</h3>
<p>c++ 창시자</p>
<blockquote>
<p>우아하고 효율적인 코드가 좋은 코드
성능을 최적으로 유지해야 사람들이 원칙 없는 최적화로 코드를 망치려는 유혹에 빠지지 않는다.</p>
</blockquote>
<ul>
<li>보기에 즐거운 코드</li>
<li>효율적인 코드</li>
<li>철저한 오류처리 - 세세한 사항까지 꼼꼼하게</li>
<li>한가지에 집중 - 각 함수와 클래스와 모듈은 주변 상황에 휘둘리지 않음</li>
</ul>
<br>

<h2 id="그래디-부치">그래디 부치</h2>
<p>object oriented analysis and design with application 저자</p>
<blockquote>
<p>깨끗한 코드는 단순하고 직접적
설계자의 의도를 숨기지 않고 오히려 명쾌한 추상화와 단순한 제어문으로 가득함</p>
</blockquote>
<ul>
<li>가독성</li>
<li>코드는 추측이 아니라 사실에 기반</li>
<li>반드시 필요한 내용만 담아야함</li>
</ul>
<br>


<h2 id="big-데이브-토마스">‘big’ 데이브 토마스</h2>
<p>OTI 창립자이자 이클립스 전략의 대부</p>
<blockquote>
<p>깨끗한 코드란 작성자가  아닌 사람도 읽기 쉽고 고치기 쉽다</p>
</blockquote>
<ul>
<li>가독성</li>
<li>테스트 케이스가 중요하다</li>
<li>큰 코드보다는 작은 코드가 낫다</li>
</ul>
<br>


<h2 id="마이클-페더스">마이클 페더스</h2>
<p>Working Effectively with Legacy Code 저자</p>
<blockquote>
<p>깨끗한 코드는 누군가 주의 깊게 짠 느낌이 드는 
고칠 곳이 없는 코드이다.</p>
</blockquote>
<ul>
<li>주의깊게 짠</li>
<li>시간을 들여 깔끔하고 단정하게 정리한 코드</li>
</ul>
<br>

<h2 id="론-제프리스">론 제프리스</h2>
<p>Extreme Programming Installed와 Extreme Programming Adventure in C# 저자</p>
<blockquote>
<p>코드 규칙</p>
</blockquote>
<ol>
<li>모든 테스트를 통과한다.</li>
<li>중복이 없다.</li>
<li>시스템 내 모든 설계 아이디어를 표현한다.</li>
<li>클래스, 메서드, 함수 등을 최대한 줄인다.</li>
</ol>
<p>중복과 표현력에 집중한다.</p>
<ul>
<li>중복을 피하라</li>
<li>한 기능만 수행하라</li>
<li>제대로 표현하라</li>
<li>작게 추상화하라</li>
</ul>
<br>

<h2 id="워드-커닝햄">워드 커닝햄</h2>
<p>위키 창시자, 피트 창시자, …, 코드를 사랑하는 프로그래머들의 대부</p>
<blockquote>
<p>코드를 읽으면서 짐작했던 기능을 각 루틴이 그대로 수행한다면 깨끗한 코드
코드가 그 문제를 풀기 위한 언어처럼 보인다면 아름다운 코드</p>
</blockquote>
<br>


<br>

<h3 id="보이스카우트-규칙">보이스카우트 규칙</h3>
<blockquote>
<p>캠프장은 처음 왔을 때보다 더 깨끗하게 해놓고 떠나라</p>
</blockquote>
<ul>
<li>체크아웃할 때보다 좀 더 깨끗한 코드를 체크인해라</li>
</ul>
<br>

<hr>
<h2 id="결론">결론</h2>
<p>사람마다 추구하는 깔끔함은 다르다.</p>
<p>절대적으로 옳은 사람은 없고 배울 수 있는 많은 전문가가 있다.</p>
<p>저자는 독자가 해당 기법에 동의하든 동의하지 않든 저자의 시각을 이해하고 존중해주기를 바란다고 했다.</p>
<p>이 책을 읽는다고 뛰어난 프로그래머가 되지 않는다</p>
<p>단지, 뛰어난 프로그래머가 생각하는 방식과 그들이 사용하는 기술과 기교와 도구를 소개할 뿐이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Flow 공부]]></title>
            <link>https://velog.io/@lee_areum/Android-Flow-%EA%B3%B5%EB%B6%80</link>
            <guid>https://velog.io/@lee_areum/Android-Flow-%EA%B3%B5%EB%B6%80</guid>
            <pubDate>Thu, 05 Jan 2023 08:02:17 GMT</pubDate>
            <description><![CDATA[<h2 id="flow">Flow</h2>
<ul>
<li>여러 값을 순차적으로 내보낼 수 있는 유형</li>
<li>비동기식으로 계산할 수 있는 데이터 스트림</li>
<li>코루틴 상에서 리액티브 프로그래밍을 지원하기 위한 구성요소</li>
</ul>
<h3 id="데이터-스트림">데이터 스트림</h3>
<p>데이터 스트림의 구성요소는 생성자, 중객자, 소비자이다.</p>
<ul>
<li>Producer(생성자) : 스트림에 추가되는 데이터 생산</li>
<li>Intermediary(중개자 - 선택사항) : 스트림에 내보내는 각각의 값이나 스트림 자체를 수정할 수 있음</li>
<li>Customer(소비자) : 스트림의 값을 사용</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lee_areum/post/1b5460d7-0195-457d-8c25-251aa52de3a9/image.png" alt=""></p>
<h3 id="리액티브-프로그래밍">리액티브 프로그래밍</h3>
<ul>
<li>데이터가 변경될 때 이벤트를 발생시켜서 데이터를 계속 전달하도록 하는 프로그래밍 방식</li>
</ul>
<h3 id="flow-만들기producer">Flow 만들기(Producer)</h3>
<ul>
<li>flow 빌더 API를 사용해서 Flow를 만들 수 있습니다.</li>
<li>emit 함수를 사용해서 새 값을 수동으로 데이터 스트림에 내보낼 수 있는 새 흐름을 만듭니다.</li>
<li>flow{} 블록 내부에서 emit()을 통해 데이터를 생성합니다.</li>
</ul>
<pre><code class="language-kotlin">class NewsRemoteDataSource(
    private val newsApi: NewsApi,
    private val refreshIntervalMs: Long = 5000
) {
    val latestNews: Flow&lt;List&lt;ArticleHeadline&gt;&gt; = flow {
        while(true) {
            val latestNews = newsApi.fetchLatestNews()
            emit(latestNews) // Emits the result of the request to the flow
            delay(refreshIntervalMs) // Suspends the coroutine for some time
        }
    }
}

// Interface that provides a way to make network requests with suspend functions
interface NewsApi {
    suspend fun fetchLatestNews(): List&lt;ArticleHeadline&gt;
}</code></pre>
<h3 id="스트림-수정intermediary">스트림 수정(Intermediary)</h3>
<ul>
<li>중간 연산자를 사용하여 값을 소비하지 않고도 데이터 스트림을 수정할 수 있습니다.</li>
<li>ex) map(데이터 변형), filter(데이터 필터링), onEach(모든 데이터마다 연산 수행)</li>
</ul>
<pre><code class="language-kotlin">class NewsRepository(
    private val newsRemoteDataSource: NewsRemoteDataSource,
    private val userData: UserData
) {
    /**
     * Returns the favorite latest news applying transformations on the flow.
     * These operations are lazy and don&#39;t trigger the flow. They just transform
     * the current value emitted by the flow at that point in time.
     */
    val favoriteLatestNews: Flow&lt;List&lt;ArticleHeadline&gt;&gt; =
        newsRemoteDataSource.latestNews
            // Intermediate operation to filter the list of favorite topics
            .map { news -&gt; news.filter { userData.isFavoriteTopic(it) } }
            // Intermediate operation to save the latest news in the cache
            .onEach { news -&gt; saveInCache(news) }
}</code></pre>
<h3 id="flow-수집customer">Flow 수집(Customer)</h3>
<ul>
<li>터미널 연산자를 사용해 값 수신 대기를 시작하는 flow를 트리거합니다.</li>
<li>collect를 사용해서 전달된 데이터를 사용합니다.</li>
<li>collect는 정지 함수 → 코루틴 내에서 실행해야 합니다.</li>
</ul>
<pre><code class="language-kotlin">class LatestNewsViewModel(
    private val newsRepository: NewsRepository
) : ViewModel() {

    init {
        viewModelScope.launch {
            // Trigger the flow and consume its elements using collect
            newsRepository.favoriteLatestNews.collect { favoriteNews -&gt;
                // Update View with the latest favorite news
            }
        }
    }
}</code></pre>
<h3 id="예외-포착">예외 포착</h3>
<ul>
<li>예기치 않은 예외를 처리하려면 catch 중간 연산자를 사용합니다.</li>
<li>catch는 항목을 흐름에 emit할 수도 있습니다.</li>
</ul>
<pre><code class="language-kotlin">class LatestNewsViewModel(
    private val newsRepository: NewsRepository
) : ViewModel() {

    init {
        viewModelScope.launch {
            newsRepository.favoriteLatestNews
                // Intermediate catch operator. If an exception is thrown,
                // catch and update the UI
                .catch { exception -&gt; notifyError(exception) }
                .collect { favoriteNews -&gt;
                    // Update View with the latest favorite news
                }
        }
    }
}</code></pre>
<h3 id="jetpack-라이브러리의-flow">Jetpack 라이브러리의 Flow</h3>
<ul>
<li>Flow는 실시간 데이터 업데이트 및 무제한 데이터 스트림에 적합합니다.</li>
<li>Flow with Room을 사용하여 데이터베이스 변경 알림을 받을 수 있습니다.<ul>
<li>DAO를 사용하는 경우 실시간 업데이트를 받으려면 Flow 유형을 반환합니다.</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">@Dao
abstract class ExampleDao {
    @Query(&quot;SELECT * FROM Example&quot;)
    abstract fun getExamples(): Flow&lt;List&lt;Example&gt;&gt;
}</code></pre>
<hr>
<h4 id="참고-사이트">참고 사이트</h4>
<p><a href="https://onlyfor-me-blog.tistory.com/478">https://onlyfor-me-blog.tistory.com/478</a></p>
<p><a href="https://developer.android.com/kotlin/flow?hl=ko">https://developer.android.com/kotlin/flow?hl=ko</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(알고리즘) 이분탐색]]></title>
            <link>https://velog.io/@lee_areum/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B4%EB%B6%84%ED%83%90%EC%83%89</link>
            <guid>https://velog.io/@lee_areum/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B4%EB%B6%84%ED%83%90%EC%83%89</guid>
            <pubDate>Mon, 19 Dec 2022 15:11:10 GMT</pubDate>
            <description><![CDATA[<h2 id="📌이분-탐색이란">📌이분 탐색이란?</h2>
<p>&quot;이분 탐색&quot;은 정렬된 배열에서 특정 값을 찾는 알고리즘입니다.</p>
<p>정렬된 배열을 이등분 하여 찾고자 하는 값이 배열의 중앙값보다 작으면 왼쪽 크면 오른쪽을 탐색하는 방식으로 값을 찾습니다.</p>
<p>시간 복잡도는 <strong>O(log N)</strong>입니다.</p>
<hr>
<h2 id="📌예시-문제">📌예시 문제</h2>
<h3 id="10815_숫자카드">10815_숫자카드</h3>
<p><a href="https://www.acmicpc.net/problem/10815">https://www.acmicpc.net/problem/10815</a>
</br></p>
<p>여기서 <strong>findCard</strong> 부분이 이진 탐색을 행하는 부분입니다.</p>
<p>이진 탐색은 반복문이나 제귀를 통해 구현할 수 있는데 
여기서는 반복문을 통해 구현했습니다.</p>
<pre><code class="language-kotlin">#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;
using namespace std;

int N,M;
vector&lt;int&gt; cards;

int findCard(int card) {
    int left = 0, right = N - 1;
    while (left &lt;= right) {
        int mid = (right + left) / 2;
        if (cards[mid] == card) return 1;
        if (cards[mid] &lt; card) {
            left = mid + 1;
        }
        else {
            right = mid - 1;
        }
    }
    return 0;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin &gt;&gt; N;
    for (int i = 0; i &lt; N; i++) {
        int n; cin &gt;&gt; n;
        cards.push_back(n);
    }
    sort(cards.begin(), cards.end());

    cin &gt;&gt; M;
    for (int i = 0; i &lt; M; i++) {
        int find; cin &gt;&gt; find;
        cout &lt;&lt; findCard(find) &lt;&lt; &quot; &quot;;
    }
    return 0;
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>