<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>King of Seoul</title>
        <link>https://velog.io/</link>
        <description>"그는 천재야"</description>
        <lastBuildDate>Mon, 26 Dec 2022 05:00:36 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>King of Seoul</title>
            <url>https://velog.velcdn.com/images/coding-whale/profile/af518d8d-3baf-4b3d-9a32-a30dc839d3d0/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. King of Seoul. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/coding-whale" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[애자일 & 스크럼 프로젝트 관리 - 3]]></title>
            <link>https://velog.io/@coding-whale/%EC%95%A0%EC%9E%90%EC%9D%BC-%EC%8A%A4%ED%81%AC%EB%9F%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B4%80%EB%A6%AC-3</link>
            <guid>https://velog.io/@coding-whale/%EC%95%A0%EC%9E%90%EC%9D%BC-%EC%8A%A4%ED%81%AC%EB%9F%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B4%80%EB%A6%AC-3</guid>
            <pubDate>Mon, 26 Dec 2022 05:00:36 GMT</pubDate>
            <description><![CDATA[<h3 id="스토리">스토리</h3>
<h4 id="사용자-스토리">사용자 스토리</h4>
<p>문장 형태로 작성된 백로그를 사용자 스토리라고 한다. 사용자에게 가치를 주는 기능을 문장으로 서술한 것이다. 이런 문장 형태의 기술 방식은 팀이 요구사항을 더 구체적으로 이해할 수 있도록 돕는다. 스토리는 아래와 같이 서술한다.</p>
<blockquote>
<p>(누가)(비즈니스 가치)를 위해 (어떤 기능)을 원한다.</p>
</blockquote>
<h4 id="완료-조건">완료 조건</h4>
<p>사용자 스토리의 완성 여부를 객관적으로 확인할 수 있는 조건이다. 고객과의 커뮤니케이션이 활발해도 완료 조건이 명확하지 않으면 서로 다른 생각을 가질 수 있다. 하지만 이 역시 초기에 명확하게 적기는 어렵기 때문에 대략적으로 적고 스프린트 계획 단계에서 상세히 적는다. 참고사항이 있다면 함께 적는다.</p>
<h4 id="기술-스토리">기술 스토리</h4>
<p>사용자 스토리를 지원하는 기술적, 관리적 업무를 서술한다. 고객이 이해할 수 있는 수준으로 작성한다.</p>
<blockquote>
<ul>
<li>요구 분석, 아키텍쳐 설계 등 기술적인 활동</li>
</ul>
</blockquote>
<ul>
<li>비기능 요구사항, 인프라 개선 활동</li>
<li>코드 리뷰, 리팩토링 등 품질 개선 활동</li>
<li>버그 수정, 모듈 안정화 등 사용성 개선 활동</li>
</ul>
<p>기술 스토리는 사용자 스토리와 다르게 개발 조직이 중심이 되어 도출한다. 기술 스토리도 일정, 비용을 추정하는 기준이 된다.</p>
<h3 id="백로그-작성-지침">백로그 작성 지침</h3>
<h4 id="independent">Independent</h4>
<p>스토리 간의 의존성을 제거하여 추정과 우선순위 선정에서 문제가 되지 않도록 해야 한다. 두 가지 사용자 스토리 구현 시 공통된 작업 요소가 있다면 스토리 하나에만 포함하고, 나머지 스토리에는 그것을 활용하도록 가정해야 한다.</p>
<h4 id="negotiable">Negotiable</h4>
<p>언제든 변경될 수 있어야 한다. 사용자 스토리는 처음에 상세하게 기술하지 않고 스프린트 계획 단계에서 도출하도록 한다.</p>
<h4 id="valuable">Valuable</h4>
<p>사용자에게 가치 있어야 하고 이해할 수 있는 언어로 작성되어야 한다. 개발 조직만 아는 언어로 작성하면 사용자가 이해하기 어렵다. </p>
<h4 id="estimable">Estimable</h4>
<p>규모와 비용을 추정할 수 있어야 한다. 에픽과 피처 단위는 추정하기 어려우므로 더 분할해야 한다.</p>
<h4 id="small">Small</h4>
<p>규모가 너무 크면 추정이 어렵고, 너무 작으면 개수가 늘어나 관리 노력이 증가한다. 스프린트 내에서 끝낼 수 있도록 적절한 분할과 병합이 필요하다. </p>
<h4 id="testable">Testable</h4>
<p>추상적인 스토리는 테스트 케이스 작성에 어려움을 초래한다. 객관적인 완료 조건이 필요하다.</p>
<h3 id="스토리-포인트">스토리 포인트</h3>
<p>스토리 포인트는 요구사항의 규모를 측정하는 단위로, 요구사항의 복잡도에 따른 업무량이다. 높은 스토리 포인트는 큰 공수라고 판단할 수 있다. 스토리 포인트는 상대적인 개념이다. </p>
<blockquote>
<p>노루, 사자, 코끼리의 무게는 직접 측정하기 전 까지 알 수 없다. 하지만 어떤 동물이 더 무거울지는 예측이 가능하다. 노루의 무게를 1이라고 가정했을 때 사자는 약 5배 무거울 것 같으므로 5, 코끼리는 13배 무거울 것 같으므로 13이라고 표현할 수 있다.</p>
</blockquote>
<p>스토리 포인트는 이런 개념을 이용해 가장 공수가 적게 드는 스토리를 기준으로 상대적인 규모를 예측한다. 기준이 되는 스토리를 선정하고 다른 스토리들은 기준 스토리와 비교해 상대적인 포인트를 부여한다. 이 때 스토리 포인트의 일관성이 유지되는지 돌아보고 필요하면 다시 추정해야 한다. 
스토리 포인트와 공수는 다른 개념이다. 보통 공수는 MD(Man Days)로 표현한다. 하지만 동일한 스토리 포인트여도 할당된 사람의 기량에 따라 MD는 달라질 수 있다. 그러므로 반드시 상대평가를 통해 스토리 포인트를 추정해야 한다. </p>
<h3 id="우선순위">우선순위</h3>
<p>우선순위가 낮은 요구사항에 시간이 많이 소비한다면 제품은 완성되지 못한 채 프로젝트가 마감이 될 것이다. 애자일은 사용자에게 가치 있는 제품을 빠르게 전달하는 것이 목표이기 때문에 우선순위 설정이 필요하다.</p>
<h4 id="moscow-우선순위">MosCow 우선순위</h4>
<p>필수, 중요, 선택 보류 네 가지로 분류한다.</p>
<h4 id="가치-점수-활용">가치 점수 활용</h4>
<p>스토리 포인트와 유사하게 가장 비즈니스 가치가 낮은 기능을 1로 두고 상대적인 가치를 추정하여 우선순위를 설정한다.</p>
<h4 id="가치-점수와-스토리-포인트-동시에-고려하기">가치 점수와 스토리 포인트 동시에 고려하기</h4>
<p>두 가지를 모두 고려하여 투입대비 가치가 높은 것을 기준으로 우선순위를 설정할 수 있다.</p>
<h3 id="배포-계획을-이용한-전체-일정-수립">배포 계획을 이용한 전체 일정 수립</h3>
<p>프로젝트 일정 관리의 기준이 되는 배포 계획은 여섯 단계로 진행된다.</p>
<blockquote>
<ol>
<li>제품 백로그 작성</li>
<li>스토리 포인트 추정</li>
<li>스프린트 기간 설정</li>
<li>평균 개발 속도 (velocity) 추정 - 한 스프린트에 완료할 수 있는 스토리 포인트의 합을 말한다.</li>
<li>전체 일정 추정</li>
<li>스토리 우선순위 설정</li>
</ol>
</blockquote>
<h3 id="스프린트-계획을-이용한-단기-일정-수립">스프린트 계획을 이용한 단기 일정 수립</h3>
<p>스프린트 계획의 목적은 어떤 작업을 수행하고, 최적의 방법으로 수행하도록 하는 것이다. 이도 여섯 단계로 진행된다.</p>
<blockquote>
<ol>
<li>백로그 정제 미팅</li>
<li>스프린트 목표, 범위 설정</li>
<li>스프린트 백로그 도출</li>
<li>평균 투입공수 추정</li>
<li>담당자 할당 - 자기 조직화를 적용했기 때문에 팀원이 원하는 작업을 할당하는 것이 맞으나 리더는 업무가 불균형하게 진행되지 않도록 조정해야 한다.</li>
<li>스프린트 목표 업무량 결정</li>
</ol>
</blockquote>
<h3 id="킥오프">킥오프</h3>
<p>이해관계자를 모두 모아서 프로젝트의 목표와 진행 방법, 책임과 역할을 공유하는 활동을 말한다. 프로젝트의 개발 방법론 이해와 주요 이슈 토론을 포함해야 한다. 이로 인해 시간이 길어질 수 있다. 킥오프에선 보통 다음 활동을 진행한다.</p>
<blockquote>
<ul>
<li>프로젝트 목적, 범위, 전략, 배포 일정 소개</li>
</ul>
</blockquote>
<ul>
<li>개발 방법론과 구성원간 책임과 역할 소개</li>
<li>이슈, 리스크 도출, 해결 방안 탐색</li>
</ul>
<p>요구사항 관리 방법에 대해 구성원간 공감대가 형성되지 않으면 프로젝트가 진행되는 동안 갈등이 발생한다. 이런 활동들을 통해 구성원들이 역할과 책임을 갖도록 해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[애자일 & 스크럼 프로젝트 관리 - 2]]></title>
            <link>https://velog.io/@coding-whale/%EC%95%A0%EC%9E%90%EC%9D%BC-%EC%8A%A4%ED%81%AC%EB%9F%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B4%80%EB%A6%AC-2</link>
            <guid>https://velog.io/@coding-whale/%EC%95%A0%EC%9E%90%EC%9D%BC-%EC%8A%A4%ED%81%AC%EB%9F%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B4%80%EB%A6%AC-2</guid>
            <pubDate>Tue, 29 Nov 2022 08:24:39 GMT</pubDate>
            <description><![CDATA[<h3 id="개발-방법론은-어떻게-활용해야-하는가">개발 방법론은 어떻게 활용해야 하는가?</h3>
<h4 id="방법론에서-제시하는-산출물을-어떻게-활용할지-따져야-한다">방법론에서 제시하는 산출물을 어떻게 활용할지 따져야 한다.</h4>
<p>낭비를 최소화하는 관점에 따라 개발 조직이나 고객에게 큰 가치를 제공하지 못 하는 프로세스는 줄이거나 없애는 것이 바람직하다.</p>
<h4 id="같은-방법론을-개발-기간-내내-동일하게-가져가선-안-된다">같은 방법론을 개발 기간 내내 동일하게 가져가선 안 된다.</h4>
<p>프로젝트 진행에 따라 환경도 계속 변화하기 때문에 주기적으로 프로세스를 평가, 개선할 필요가 있다.</p>
<h3 id="애자일">애자일</h3>
<h4 id="스프린트">스프린트</h4>
<p>애자일 방법론은 스프린트 단위로 요구사항의 변화를 받아들이며 개발한다.
스프린트를 계획하며 이전 요구사항과 새 요구사항을 보고 우선순위를 따져 작업하기 때문에 작업 중간에 요구사항이 바뀐다고 해도 다음 스프린트에 포함하면 그만이다.
이런 식으로 업무를 진행하면 결과적으로 우선순위가 떨어지는 요구사항은 프로젝트에 포함되지 않게 된다.</p>
<h4 id="폭포수-방식이-아님">폭포수 방식이 아님</h4>
<p>스프린트에도 물론 분석, 설계, 구현, 테스트의 공정이 발생한다.
하지만 폭포수 모델과의 차이점은 공정에 정해진 순서가 없다는 것이다.
고객에게 중요한 것은 중간 산출물이 아닌 결과물이라고 보기 때문에 모든 공정은 동시적으로 발생하여 중간 산출물을 최소화하고 제품의 품질을 높이는 것에 초점을 맞춘다.</p>
<h4 id="주기가-규칙적-타임-박싱">주기가 규칙적 (타임 박싱)</h4>
<p>스프린트는 빌드 기준으로 돌아가는 것이 아닌 2~4주 정도의 시간을 기준으로 돌아간다.
빌드 기준으로 개발 주기를 돌리면, 빌드의 규모에 따라 개발 주기가 들쭉날쭉하게 된다.
이런 규칙적인 개발 주기를 애자일에서는 타임 박싱이라고 표현하며, 이로 인해 업무 예측에 도움이 될 수 있다.</p>
<h3 id="요구사항-도출">요구사항 도출</h3>
<h4 id="린-스타트업">린 스타트업</h4>
<p>요구사항 도출을 프로젝트 초기에만 국한하지 않고 주기적은 피드백을 통해 진행한다.
또한 언제든 요구사항이 바뀔 수 있다는 것을 전제로 둔다.
추후 변경되는 사항이 발생할 때를 대비해 프로젝트 초기에 상세한 요구사항을 모두 도출하지 않는다. 초기에 설정한 요구사항이 항상 정답은 아니기 때문이다.</p>
<p>고객은 제품을 원하지만, 정확하게 무엇을 원하는지는 알 수 없다. 전문가 또한 본인의 분야에 매몰되어 있을 가능성이 있다. 이를 해결하기 위해 요구사항 도출 과정에서 고객과 다양한 팀원들이 함께 참여한다. 고객이 인지하지 못 하는 문제를 도출할 수 있으며, 고객의 니즈를 다양한 측면에서 바라보기 때문에 창의적인 아이디어가 나올 수 있다.</p>
<h4 id="디자인-씽킹">디자인 씽킹</h4>
<p>디자인 씽킹은 본질적인 문제를 파악하는 데에 중점을 둔다.
린 스타트업과 비슷하지만 &#39;공감&#39;이라는 과정이 추가된다.
공감은 관찰, 체험, 인터뷰 등으로 진행되나, 고객의 상황을 이해하고 유대감을 가지는 데에 중점을 두어 진행한다. 고객의 입장을 이해해야 본질적인 문제를 찾기 쉽기 때문이다.</p>
<blockquote>
<p>내 자랑 😋✌️
창업을 하고 MVP를 개발하던 당시, 예상되는 사용자 표본들을 섭외해 인터뷰를 진행했다. 그들은 불편한 점은 있지만, 무엇이 어떻게 불편한지에 대해서는 정확하게 인지하지 못 한 상태였다. 인터뷰 이후 알게 된 고객 입장을 고려해 요구사항을 도출했고, 서비스는 사용자들에게 긍정적인 평가를 받았다. </p>
</blockquote>
<h3 id="요구사항-정의와-백로그">요구사항 정의와 백로그</h3>
<p>애자일에서 요구사항은 백로그에 작성한다.
백로그는 개발에 필요한 모든 업무를 우선순위화한 목록이며 백로그에 포함되는 요소들은 다음과 같다.</p>
<ul>
<li>요구 기능, 비기능 요구사항</li>
<li>기술적, 관리적 업무</li>
<li>문제 해결 (리팩토링)</li>
<li>버그 수정</li>
</ul>
<p>애자일은 변화를 주기적으로 수용해야 하기 때문에 요구 기능을 중심으로 백로그를 작성하고 선행 작업은 기술하되, 세부 작업은 백로그에 포함하지 않는다. 세부 작업은 스프린트에서 도출되며, 이런 방법은 추후 요구사항 변경에 대해 용이하게 대처할 수 있도록 한다.</p>
<p>요구사항을 정의하면 시장 가치가 높은 것을 우선으로 스프린트를 거쳐 MVP를 개발하고, 시장의 피드백을 받으며 지속적으로 개선해 프로젝트를 완수한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[애자일 & 스크럼 프로젝트 관리 - 1]]></title>
            <link>https://velog.io/@coding-whale/%EC%95%A0%EC%9E%90%EC%9D%BC-%EC%8A%A4%ED%81%AC%EB%9F%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B4%80%EB%A6%AC</link>
            <guid>https://velog.io/@coding-whale/%EC%95%A0%EC%9E%90%EC%9D%BC-%EC%8A%A4%ED%81%AC%EB%9F%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B4%80%EB%A6%AC</guid>
            <pubDate>Fri, 25 Nov 2022 07:43:05 GMT</pubDate>
            <description><![CDATA[<h3 id="프로젝트는-복잡적응계다">프로젝트는 복잡적응계다</h3>
<p>프로젝트는 초기 요구사항의 불확실성, 팀의 역량, 기술적 리스크 등의 여러 요인이 상호 작용하기 때문에 일정과 비용에 대해 정확한 예측이 불가능하다. 그러므로 상황에 따라 최적의 방법을 찾아야 한다.</p>
<blockquote>
<p>하나의 태스크조차 예측이 쉽지 않은데, 그 태스크들의 집합인 프로젝트에 대해서는 예측이 가능할까?</p>
</blockquote>
<p>애자일은 프로젝트를 복잡적응계로 인식한다. 프로젝트 성공으로 가는 절대적인 방법이 있다는 가정을 하지 않는다. 주변 환경이 불안정하고 변화가 잦을수록 경험적 프로세스가 훨씬 효과적이다. 애자일은 <strong>관찰과 적응으로 지속적으로 개선하는 경험적 프로세스</strong>다.</p>
<h3 id="자기-조직화된-팀">자기 조직화된 팀</h3>
<p>관리자의 지시가 아닌 스스로 해야 할 일을 계획하고 협업하여 업무를 수행하는 팀의 형태를 자기 조직화된 팀이라고 한다. 자기 조직화가 되면 예기치 않은 일이 발생했을 때 <strong>리드의 부재에도 적절한 대응</strong>이 가능하다. 자기 조직화의 예시로는 철새의 군무가 있다.
자기 조직화된 팀을 만들기 위해서는 구성원들에게 책임감과 자율성을 부여하고 이를 유지할 수 있도록 지원해야 한다.</p>
<h3 id="린">린</h3>
<h4 id="도요타가-세계적인-자동차-회사가-될-수-있었던-이유">도요타가 세계적인 자동차 회사가 될 수 있었던 이유</h4>
<p>기존 테일러리즘식 생산 방식이 지배하던 시장에서 도요타는 관점의 전환으로 크게 성장했다. 이 방식은 린 시스템이라고 일컬어지며 많은 영향을 주었다.</p>
<h4 id="장비의-가동률보다-제품의-리드-타임을-줄이는-데-초점을-맞추다">장비의 가동률보다 제품의 리드 타임을 줄이는 데 초점을 맞추다</h4>
<p>가동률을 높여 대량 생산하는 기존의 방식은 과잉 생산, 결함의 잠복을 초래했다. 대량 작업은 배치로 진행되어 리드 타임이 길고 결함 여부도 최종 과정 (조립, 테스트) 단계에서나 파악할 수 있었다. 하지만 도요타는 제품 단위당 생산으로 리드 타임과 결함 여부를 더 빠르게 취할 수 있었다.</p>
<blockquote>
<p>자동차 생산 과정에 &#39;부품 생산&#39;, &#39;도색&#39;, &#39;조립&#39; 이라는 3개의 공정이 있다고 예를 들어보자. 10대의 자동차를 생산해야 한다.
&#39;기존 생산 방식&#39;은 다음과 같았다.
[부품 생산 * 10] &gt; [도색 * 10] &gt; [조립 * 10]
조립은 10대분의 부품이 모두 도색되어야지만 진행되어 지연이 발생한다. 그리고 부품 생산에서 결함이 발생했더라도 조립 공정으로 넘어가야지만 결함을 확인할 수 있다.
하지만 도요타는 아래와 같은 프로세스로 자동차를 생산했다.
[부품 생산 + 도색 + 조립] * 10
공정과 공정 사이 딜레이가 적고, 차량에 결함이 있는 경우 더 신속하게 대응할 수 있었다.</p>
</blockquote>
<h4 id="생산-근로자를-업무-개선에-있어-부가가치-창출의-원천으로-보다">생산 근로자를 업무 개선에 있어 부가가치 창출의 원천으로 보다</h4>
<p>기존에는 공정 설계자와 실행자가 분리되어 있었다. 실행자는 설계자가 정해 둔 규칙에 따라서만 작업했다. 하지만 도요타는 실행자에게 학습을 권장하고 동기부여를 해 그들이 스스로 공정을 효율적으로 진행할 수 있도록 했다. </p>
<h3 id="몰입">몰입</h3>
<h4 id="1-명확한-목표">1. 명확한 목표</h4>
<p>구성원이 프로젝트에서 오너쉽을 가질 수 있도록 명확한 목표를 제시해야 한다. 리드가 일방적으로 정하지 않아야 하며 자유롭게 토론하고 주기적으로 목표를 공유해야 한다.</p>
<h4 id="2-자율성">2. 자율성</h4>
<p>특정 방법론이나 특정 시간과 장소에서만 업무를 진행하도록 하는 제약은 개인의 능률을 저하시키는 결과를 가져온다. 리드는 방향을 이끌어야 하는 역할이지, over-control은 팀원의 책임감을 떨어트린다. 하지만 이는 개인마다 다를 수 있으며 미숙한 팀원의 경우 조금 더 상세한 가이드가 필요하다.</p>
<h4 id="3-피드백">3. 피드백</h4>
<p>몰입하기 위해선 주기적인 피드백이 필요하다. 동료와 이해관계자로부터의 주기적인 피드백은 업무 추진에 대해 자신감과 관심을 발생시킨다.</p>
<h4 id="4-과제와-역량의-균형">4. 과제와 역량의 균형</h4>
<p>팀 또는 개인의 역량에 비해 과도한 양과 난이도의 과제는 불안감을 야기한다. 반대의 경우는 권태를 느껴 몰입에 방해를 준다. 업무를 할당할 땐 각자의 역량에 비례해 적절한 업무를 할당해야 한다. 프로젝트에서는 이런 work load를 적절히 관리해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[트랜잭션과 Django의 transaction.atomic에 대해 알아보자]]></title>
            <link>https://velog.io/@coding-whale/Django%EC%9D%98-transaction-atomic%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@coding-whale/Django%EC%9D%98-transaction-atomic%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Tue, 20 Sep 2022 08:03:55 GMT</pubDate>
            <description><![CDATA[<p>백엔드 개발을 하면 언젠가는 트랜잭션과 마주하게 된다.
장고에서 트랜잭션을 어떻게 관리하는지에 대해 알아보자.
급하다면 <code>6. Django ORM의 트랜잭션</code>부터 ...</p>
<h2 id="1-트랜잭션transaction이-무엇일까">1. 트랜잭션(transaction)이 무엇일까.</h2>
<p>트랜잭션은 <strong>DB의 상태를 변화시키기 위해 수행하는 작업의 단위</strong>이다.
SQL을 이용한 CRUD가 그 작업들이다.</p>
<p>하지만 하나의 쿼리가 하나의 트랜잭션인 것은 아니며, 여러 쿼리를 묶어 하나의 트랜잭션으로 처리할 수 있다.
아래와 같은 상황을 가정을 해보겠다.</p>
<blockquote>
<p>서비스 내 재화를 소비하여 물품을 구매하는 로직을 구현해야 한다.</p>
</blockquote>
<ol>
<li><code>cash</code> 테이블에서 잔액을 조회한다.</li>
<li>재화를 소비하고 잔액을 <code>update</code>한다.</li>
<li>구매 내역을 생성한다.</li>
<li>소비 이후 잔액을 조회한다.</li>
</ol>
<p>위와 같은 로직을 구현했을 때 아래와 같은 순서로 쿼리가 발생한다.
(실제 서비스라면 더 많은 쿼리들이 발생하겠지만, 예시이니 간단하게만)</p>
<p><img src="https://velog.velcdn.com/images/coding-whale/post/a0251699-23f2-498c-bb0e-b29babfc2048/image.jpeg" alt=""></p>
<p>이 때 발생할 수 있는 문제들을 생각해보면,</p>
<blockquote>
<p>재화를 소비하는 로직이 동시에 발생하면 어떡하지?
잔액 부족이나 특정 이유로 재화를 소비할 수 없는 상황이 발생하면 어떡하지?
잔액과 구매 내역이 같지 않으면 어떡하지?
...
<strong>문제가 발생했을 때 어떻게 되돌리지...</strong></p>
</blockquote>
<h2 id="2-어떻게-되돌리지">2. 어떻게 되돌리지...</h2>
<p>아래와 같이 하나의 트랜잭션으로 처리하면 가능하다.
<img src="https://velog.velcdn.com/images/coding-whale/post/aa61aa4a-63a4-4899-8f1b-076342b26eac/image.jpeg" alt=""></p>
<p>하지만 어떻게?
트랜잭션의 특성, <code>commit</code>과 <code>rollback</code>에 대해 먼저 간단히 알아보겠다.</p>
<h2 id="3-트랜잭션의-특성">3. 트랜잭션의 특성</h2>
<p>트랜잭션은 아래 4가지 특성을 가진다.</p>
<ol>
<li><p>원자성 (Actomicity)
트랜잭션의 수행 결과는 <strong>전부 반영되거나, 전부 반영되지 않아야 한다.</strong></p>
</li>
<li><p>일관성 (Consistency)
트랜잭션 작업의 결과는 항상 일관되어야 한다.</p>
</li>
<li><p>독립성 (Isolation)
각각의 트랜잭션은 서로 간섭할 수 없이 독립적이다.</p>
</li>
<li><p>영구성 (Durability)
트랜잭션이 성공적으로 처리되면 <strong>결과는 영구적으로 반영되어야 한다.</strong></p>
</li>
</ol>
<p>혹시 감이 오는지?
이번 포스트에서는 원자성, 영구성에 대해 다룬다.</p>
<h2 id="4-commit과-rollback">4. commit과 rollback</h2>
<p>트랜잭션이 종료될 때 아래와 같은 연산들을 한다.</p>
<ol>
<li><p>commit
트랜잭션이 성공적으로 끝나서 결과에 대해 <strong>영구성을 보장하도록 한다.</strong></p>
</li>
<li><p>rollback
트랜잭션이 <strong>원자성을 보장할 수 없을 때</strong> 수행하여 재시도하거나 되돌릴 수 있도록 한다.</p>
</li>
</ol>
<h2 id="5-그렇다면">5. 그렇다면</h2>
<p>성공적으로 수행되면 <code>commit</code>하고, 문제가 발생하면 <code>rollback</code>하여 상황을 해결할 수 있다!
너무 간단한데...
<code>Django</code>에서는 어떨까?</p>
<h2 id="6-django-orm의-트랜잭션">6. Django ORM의 트랜잭션</h2>
<p><code>Django</code>는 기본적으로 <code>autocommit</code>이다.
각 ORM(쿼리)가 실행되는 즉시 DB에 <code>commit</code>을 해버리는 방식이다.
명시적으로 트랜잭션을 제어하기 위해선 <code>atomic</code>을 사용해야 한다.</p>
<h3 id="atomic">atomic</h3>
<p>이름에서부터 알 수 있듯이 <code>atomic</code>을 사용해 원자성을 보장하는 코드 블록을 만들 수 있다.
<code>atomic</code>으로 묶여있는 코드 블록은 하나의 트랜잭션으로 동작한다.
해당 코드 블록이 성공적으로 수행되면 <code>commit</code>, 그렇지 않으면 <code>rollback</code>한다.</p>
<p><code>atomic</code>을 사용하여 1장에서 정의된 상황에 하나의 요구사항을 추가해 간단하게 구현해보겠다.</p>
<blockquote>
<p>서비스 내 재화를 소비하여 물품을 구매하는 로직을 구현해야 한다.</p>
</blockquote>
<ol>
<li><code>cash</code> 테이블에서 잔액을 조회한다.</li>
<li>재화를 소비하고 잔액을 <code>update</code>한다.</li>
<li>상품이 구매 가능한 상태라면 구매 내역을 생성한다.</li>
<li>그렇지 않다면 구매를 취소한다.</li>
<li>구매 이후 잔액을 조회한다.</li>
</ol>
<pre><code class="language-python">from django.db import transaction

def 잔액_확인(유저):
    return Cash.objects.get(유저=유저).잔액

def 구매내역_생성(유저, 상품):
    if 상품.구매_가능:
        purchase_history = PurchaseHistory.objects.create(
            유저=유저,
            상품=상품
        )

        return purhcase_history

    raise Exception(f&quot;현재 {상품.이름}을 구매할 수 없습니다.&quot;)

@transaction.atomic
def 구매(유저, 상품):
    잔액 = 잔액_확인(유저)
    if 잔액 &lt; 상품.가격:
        raise Exception(&quot;잔액이 부족합니다.&quot;)

    재화_소비(상품.가격)
    구매내역_생성(상품)

    return 잔액_확인(유저)</code></pre>
<p>먼저 현재 잔액이 부족한 경우와 상품이 구매가 가능하지 않은 경우 의도적으로 <code>raise</code>를 해주었다.
그렇다면 트랜잭션은 <code>rollback</code>되고 유저의 잔액은 정상적으로 유지가 될 것이다.
문제 없이 마지막 코드까지 실행되면 결과는 <code>commit</code>되어 생성된 구매내역과 잔액은 영구성이 보장 될 것이다.</p>
<h3 id="with로-사용하기">with로 사용하기</h3>
<p><code>atomic</code>은 <code>decorator</code> 이외에도 <code>with</code>와 함께 사용할 수 있다.</p>
<pre><code class="language-python">def 구매(유저, 상품):
    with transaction.atomic():
        잔액 = 잔액_확인(유저)
        if 잔액 &lt; 상품.가격:
            raise Exception(&quot;잔액이 부족합니다.&quot;)

        재화_소비(상품.가격)
        구매내역_생성(상품)

        return 잔액_확인(유저)</code></pre>
<p>상황에 맞게 사용하면 되겠지만, <code>with</code>를 사용하면 <code>indent</code>가 늘어나 나는 <code>decorator</code>를 선호한다.</p>
<h3 id="on_commit">on_commit</h3>
<p>트랜잭션이 정상적으로 <code>commit</code>될 때 수행할 내용도 지정할 수 있다.
구매에 성공하면 유저에게 구매 완료 이메일을 발송하는 셀러리 태스크를 호출한다고 해보자.</p>
<pre><code class="language-python">from functools import partial

def 구매(유저, 상품):
    with transaction.atomic():
        잔액 = 잔액_확인(유저)
        if 잔액 &lt; 상품.가격:
            raise Exception(&quot;잔액이 부족합니다.&quot;)

        재화_소비(상품.가격)
        구매내역_생성(상품)

        transaction.on_commit(partial(구매_완료_이메일_발송.delay, 유저.이메일))

        return 잔액_확인(유저)</code></pre>
<p>아... 초간단.</p>
<h2 id="7-맺는-말">7. 맺는 말</h2>
<p>쉽다.
다음번엔 lock에 대해서 다뤄볼까 한다.
자세한 내용은 <a href="https://docs.djangoproject.com/en/4.1/topics/db/transactions/">https://docs.djangoproject.com/en/4.1/topics/db/transactions/</a> 에서 확인 가능하다.</p>
<h4 id="그럼-au-revoir-🤠">그럼, Au revoir 🤠</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[2022 상반기 회고]]></title>
            <link>https://velog.io/@coding-whale/2022-%EC%83%81%EB%B0%98%EA%B8%B0-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@coding-whale/2022-%EC%83%81%EB%B0%98%EA%B8%B0-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Wed, 07 Sep 2022 14:12:26 GMT</pubDate>
            <description><![CDATA[<h2 id="회고-1">회고 #1</h2>
<h3 id="2022년-1분기">2022년 1분기</h3>
<h4 id="swift-ui">Swift UI</h4>
<p><code>Swift UI</code>를 이용해서 iOS 네이티브 앱을 개발했다. <code>socket.io</code>를 통한 채팅 앱이었는데, 소켓 연결의 관리에 많은 어려움이 있었다. 다만 UI를 개발하는데에 있어 <code>Storyboard</code>보단 탁월한 장점을 보인다는 것은 완벽하게 체감했다. 그럴 일은 없길 바라겠지만 네이티브로 iOS앱을 만들어야 할 경우가 생긴다면 그때도 어김없이 <code>Swift UI</code>를 사용할 것이다.</p>
<h4 id="knowledge-graph">Knowledge Graph</h4>
<p><code>Neo4j</code>를 이용해 지식그래프를 구현했다. 제품, 기업, 국가의 도메인이 있었으며 생산, 수입, 수출의 관계가 있었다. 어느 정도 모양은 나왔는데, 퍼포먼스가 너무 낮았다.</p>
<h4 id="gcp-cloud-function">GCP Cloud Function</h4>
<p>매우 간단하다. AWS의 <code>lambda</code>와 같은 기능이다. 편리하게 사용했지만 테스트를 하는 방법을 몰라 불편했다. 하지만 GCP 역시 다시는 쓸 일이 거의 없을 것 같아서 다행이다.</p>
<h4 id="gcp-natural-language-api">GCP Natural Language API</h4>
<p>요소 추출과 텍스트 분류를 진행했다. 정확도는 역시 구글답게 꽤 높지만 필요로 하는 데이터를 만들기가 많이 불편했다. 크롤링을 통해 필요한 데이터를 가져오는 것은 문제가 되지 않음에도 불구하고 해당 API에서 요구하는 포맷으로 텍스트를 라벨링하는데 많은 공수가 들었다. 만약 룰베이스로 그것이 가능하다면 그런 방법으로 다시 시도해보고 싶다.</p>
<h4 id="퇴사">퇴사</h4>
<p>약 11개월간 재직하던 회사를 떠났다. 참 좋은 결정이었다. </p>
<p>세 번째 직원으로 합류했던 그 회사는 CEO의 인맥을 통한 확실한 비즈니스 모델이 있었지만, 돌이켜 생각해보면 커리어를 쌓는 데에는 아주 극악의 환경이었다. 회사의 첫 개발자로 입사해(파이썬 백엔드) 미친듯이 굴렀다. 인력 보충은 되지 않았으며 연관 없는 업무의 연속이었다. <code>Koa.js</code>로 백엔드를 개발했고, <code>Vue.js</code>를 통해 PC 웹의 대시보드를 만들었다. 그리고 피벗. 
웹뷰로 채팅 앱을 개발했지만, 또 한 번의 피벗으로 네이티브 앱까지 개발했다.</p>
<p>기사 노릇도 했다. 서울의 꽤 유명한 호텔에 어떤 제품을 납품할 때 담당자를 태우고 <strong>내 개인 소유의 차</strong>로 다녀오는 일들이 종종 있었다. 회사 소유 창고로 제품이 들어오면 용달 아저씨와 함께 제품을 쌓았다.</p>
<p>정치도 경험했다. 이 스타트업은 성공할거라는 생각에 나는 내게 주어진 모든 업무에 No!를 하지 않고 미친듯이 일했다. 당연히 CEO와 가까워질 수 밖에 없었고, 우리 둘 사이를 질투하던 <strong>사번 2번 직원</strong>과 마찰이 잦았다.
HR, 경리 등의 업무를 맡던 그 직원에 의해 나, 내 친구가 피해를 입었고 참을 수 없었다.
마지막까지 뱀같은 그 직원의 혀에 당해 쫓겨나듯 퇴사해 백수로 지냈다.</p>
<h3 id="2022년-2분기">2022년 2분기</h3>
<h4 id="입사-지원">입사 지원</h4>
<p>참 많은 회사에 지원했다. <code>네카라쿠배당토</code> 중 한 곳 부터 작은 스타트업까지. 면접을 엄청나게 보면서 많은 팁과 좋은 회사를 고르는 방법을 터득했다. 이 방법을 미리 알았다면 참 좋았을 텐데... 하는 아쉬움도 많이 남았다. 하지만 결론적으로 먼저 나의 능력이 선행되어야 한다. 모 기업의 코딩테스트, 면접, 라이브 코딩을 진행하며 참 많이 부족하구나 느꼈다. </p>
<p>결론적으로 3곳에 최종합격했다.</p>
<h4 id="입사">입사</h4>
<p>세 회사는 각각 다른 특징을 가지고 있었다.</p>
<p>회사 N</p>
<ul>
<li>NLP, CV관련 일을 하는 팀과 함께 일할 수 있다.</li>
<li>회사가 지방에 존재한다.</li>
<li>서울과 지방의 연봉 체계는 다르다며 연봉 삭감을 요청했다.</li>
</ul>
<p>회사 A</p>
<ul>
<li>인지도가 많이 높은 편이다.</li>
<li>가장 높은 연봉을 제시했고, 비포괄임금제를 운영한다.</li>
<li>식비 무제한 등 복지가 잘 되어있다.</li>
<li>면접 경험이 부정적이었다.</li>
</ul>
<p>회사 P</p>
<ul>
<li>연봉이 애매하다.</li>
<li>정시 출퇴근에 대한 강박이 비교적 적다.</li>
<li>면접 경험이 긍정적이었다.</li>
</ul>
<p>결론적으로 회사 A와 P를 고민하던 중 P를 선택했다.
면접 때 나의 20대 목표에 대해 공유했다. 그 이야기를 들은 면접관께서 충분히 회사가 도움을 줄 수 있고 함께 성장했으면 좋겠다는 메시지를 너무 잘 전달받았다. 
<strong>그리고 현재 약 6개월간 아주 행복하게 일을 하고 있다. 야호!</strong></p>
<h4 id="graphql">GraphQL</h4>
<p>현재 내가 맡고 있는 프로젝트는 <code>GraphQL</code>로 서버와 클라이언트가 통신한다. 지금까지의 경험과 읽어본 레퍼런스, 사람들과 나눈 이야기를 통해 내린 나의 결론은 다음과 같다.</p>
<blockquote>
<p>장단점이 너무나도 명확하다.</p>
</blockquote>
<p>GraphQL로 얻는 이점은 있으나 분명 잃는 것도 있다. 그 때 상황에 맞춰가며 잘 결정해야 할 것 같다.</p>
<h4 id="ddd">DDD</h4>
<p><code>DDD</code>에 대해서는 친구 덕분에 처음 알게 되었다. 단순 도메인에 따라 분리하는 거 아닌가? 라고 생각했었지만, 이 회사에서 직접 느껴보며 &#39;아 괜히 DDD가 유행하는 것은 아니구나.&#39;라고 느꼈다. 아직 부족하지만 도메인과 레이어를 명확한 설계에 의해 아름답게 분리하고 그 위에 코드를 짜고 싶다.</p>
<h4 id="배포">배포</h4>
<p>배포 브랜치에 머지를 하면 <code>CodeBuild</code>에 의해 자동으로 배포가 이루어진다.
너무 행복하다... 동료에 의하면 <code>Github Action</code>을 통해 배포를 하는 것이 개인적으로 조금 더 재밌다던데. 지금 진행하는 프로젝트에 적용해볼까 한다.</p>
<h4 id="비동기-처리와-스케쥴링">비동기 처리와 스케쥴링</h4>
<p>내가 주로 사용하는 언어인 파이썬은 기본적으로 동기로 동작한다. 
그리고<code>Celery</code>라는 라이브러리가 그 문제를 해결하기 위해 존재한다.
<code>Celery</code>와 <code>Celery Beat</code>를 사용하면서 신세계를 경험했다.</p>
<p>하지만 ...
<code>Github Action</code>을 추천해준 동료가 <code>AWS Batch</code>와 <code>AWS lambda</code>가 더 효율적인 것 같다는 의견을 제시해서 내 세상이 조금 무너졌다.</p>
<p>한 회사 면접을 볼 때 스케쥴링에 대한 질문이 있었다. 그때 나는 <code>lambda</code>와 <code>cloudwatch</code>를 떠올렸지만, 지금 생각해보니 그때 정답은 아마 <code>celery beat</code>였지 싶다.</p>
<h4 id="test">Test</h4>
<p>테스트케이스는 정말 너무 중요하다..............</p>
<h3 id="맺음말">맺음말</h3>
<p>전 회사를 다닌 11개월보다 4월부터 6월까지 성장의 폭이 더 크다.</p>
<blockquote>
<p>과거의 나는 분명 노력했지만...</p>
</blockquote>
<p>환경탓을 과거의 나는 정말 싫어했다. 
가치도 없는 핑계라고 생각했지만,
좋은 환경을 경험해보니 환경탓은 분명 존재한다.</p>
<p>야호!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Fast API에 대해서 알아보자 (타입에 관하여)]]></title>
            <link>https://velog.io/@coding-whale/Fast-API%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@coding-whale/Fast-API%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sat, 28 May 2022 07:19:36 GMT</pubDate>
            <description><![CDATA[<h2 id="여는-말">여는 말</h2>
<p>얼마 전 회사에서 모놀리식으로 되어 있던 프로젝트를 분할하여 MSA를 도입하자는 의견이 나왔다.
그 결과 특정 도메인을 시작으로 순차적으로 MSA를 도입하기로 결정됐다.
해당 도메인을 어떤 스택으로 구현할지 고민하던 중 내 머릿속에 FastAPI가 스쳐 지나갔다.</p>
<p><em><strong>왜 FastAPI를 떠올렸는가?</strong></em>
Fast하게 가자.</p>
<h2 id="fastapi가-무엇인가">FastAPI가 무엇인가?</h2>
<p>공식 문서에서는 이 질문을 한 문장으로 설명한다.</p>
<blockquote>
<p>FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트에 기초한 Python3.6+의 API를 빌드하기 위한 웹 프레임워크입니다.</p>
</blockquote>
<p>Python 기반의 빠르고, 빠르게 개발할 수 있고, 버그가 적으며 직관적인데다가 쉽게, 짧게, 견고한 표준 기반의 프레임워크가 바로 FastAPI다.</p>
<p><em><strong>어떻게 그것이 가능한가?</strong></em>
적은 버그와 직관적인 코드에 대해 먼저 이야기해보자.</p>
<h2 id="type">Type</h2>
<p>파이썬은 인터프리터 언어이며 동적 언어이다.
변수의 타입은 선언이 아닌 실행 당시에 결정된다.</p>
<p>그렇기 때문에 아래와 같은 코드가 <strong>문법적으로는</strong> 문제가 되지 않는다.</p>
<pre><code class="language-python">tmp = 1
tmp = False
tmp = &quot;tmp&quot;
tmp = list()
tmp = dict()

print(tmp)

---
실행 결과 : {}</code></pre>
<p>나 역시도 이런 점이 파이썬의 큰 장점이라고 생각했다.</p>
<p><em>하지만 이 특징은 양날의 검과 같아서...</em>
프로젝트의 규모가 커지고, 참여하는 인원이 늘어나고, 수정사항이 반복될 때 마다 <code>TypeError</code>를 마주하는 일이 잦아졌다.</p>
<p>이런 이슈로 인해 몇 년 전, 파이썬 3.5부터 타입 힌트와 타입 어노테이션이 추가됐다.
변수와 결과에 대해 타입을 명시하니 <strong>코드는 직관적이 되고</strong>, <strong>에디터는 더 높은 수준의 보조가 가능해진다</strong>.
그리고 자연스럽게 <strong>적은 버그를 기대할 수 있다</strong>.</p>
<p><strong><em>파이썬 타입은 갑자기 왜?</em></strong>
왜냐하면...</p>
<h2 id="fastapi의-type">FastAPI의 Type</h2>
<p>앞서 FastAPI는 파이썬 표준 타입 힌트에 기초했다는 말을 떠올려보라.
조금 이상하지 않은가?</p>
<p>타입 힌트는 FastAPI의 요소가 아닌 파이썬의 문법 중 하나인데, 왜 그런 말을 했을까?
Django나 Flask에서도 사용할 수 있는데.</p>
<p>공식 문서에 나와있는 Path Parameter를 통해서 간단하게 설명해보겠다.</p>
<pre><code class="language-python">from fastapi import FastAPI

app = FastAPI()


@app.get(&quot;/items/{item_id}&quot;)
async def read_item(item_id: int):  # item_id를 int로 선언!
    return {&quot;item_id&quot;: item_id}</code></pre>
<p>위는 <code>/items/{item_id}</code>로 get 요청을 하면 item_id를 반환하는  아주 간단한 예시이다.</p>
<p>예제를 run하고 <code>/items/3</code>에 get 요청을 보내보자. <code>{&quot;item_id&quot;: 3}</code>가 반환된다.
<strong><code>/items/hello</code>로 요청을 하면<code>TypeError</code>가 발생한다!</strong></p>
<p>기본적으로 Path Parameter는 <code>string</code>이다.</p>
<p>보통의 경우 <code>item_id</code>를 목적에 맞게 사용하기 위해선 <code>int</code>로 캐스팅이 필요하지만, FastAPI에선 선언된 타입으로 알아서 캐스팅을 진행한다. </p>
<p><code>item_id</code>를 <code>int</code>로 선언을 했기 때문에 <code>/items/3</code>은 정상적으로 동작하고 <code>/items/hello</code>는 hello를 <code>int</code>로 캐스팅 할 수 없기 때문에 <code>TypeError</code>를 뱉은 것이다.</p>
<p>첫 번째 요청에서의 반환값을 보라.
<code>{&quot;item_id&quot;: 3}</code>에서 3이 <code>string</code>이 아니다. (따로 캐스팅을 해주지 않았음에도 불구하고)</p>
<p>이것이 표준 타입 힌트에 기초한 FastAPI의 장점이다.</p>
<h2 id="맺는-말">맺는 말</h2>
<p>FastAPI의 타입 검증은 <a href="https://pydantic-docs.helpmanual.io/"><code>pydantic</code></a>에 기초한다.
엄밀히 말하면 <code>pydantic</code>은 검증이 아닌 파싱을 위한 용도로 사용되는데, 이 과정에서 변수에 선언된 타입과 맞지 않는 값을 넣는 경우 캐스팅에 실패해 <code>TypeError</code>가 발생하는 원리다.</p>
<h3 id="그럼-fast-⚡"><strong>그럼, Fast! ⚡</strong></h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[GIL에 대해서 알아보자]]></title>
            <link>https://velog.io/@coding-whale/GIL%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@coding-whale/GIL%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sun, 03 Apr 2022 07:00:09 GMT</pubDate>
            <description><![CDATA[<p>파이썬을 사용하다 보면 GIL과 마주하게 되는 상황이 온다.
멀티 쓰레딩을 하게 되면 오히려 실행 시간이 길어지는 경우가 있는데, 그 이유는 <strong>GIL</strong> 때문이다.</p>
<h3 id="gil이-무엇일까">GIL이 무엇일까?</h3>
<p>GIL은 Global Interpreter Lock으로 이름의 뜻으로만 본다면 인터프리터 전역에 수행하는 일종의 락임을 유추할 수 있다. 
실제로 GIL은 여러 개의 쓰레드가 파이썬 코드를 병렬로 실행할 수 없도록 하는 역할을 한다. 
그 말은 멀티 쓰레딩으로 코드를 작성해도 한 번에 하나의 쓰레드만 실행된다는 말이 된다. </p>
<h3 id="그렇다면-gil은-왜-있을까">그렇다면 GIL은 왜 있을까?</h3>
<p>그 이유를 알기 전에 <code>Reference Count</code>에 대해 알고 있어야 한다. 
파이썬에서는 모든 것이 객체로써 존재하는데, 그 객체들은 <code>Reference Count</code>를 가지고 있다. 파이썬의 가비지 컬렉터는 해당 객체의 <code>Reference Count</code>가 0이 되면 메모리에서 삭제하는 방식으로 동작한다.</p>
<p><strong>이것이 GIL이 존재하는 이유다.</strong></p>
<p>여러 쓰레드에서 동시에 인터프리터를 실행하면 <code>Race Condition</code>이 발생할 수 있다. <code>Reference Count</code>가 잘못 관리될 수 있고 이로 인해 가비지 컬렉터가 정상적으로 작동하지 않을 가능성이 생긴다.
<code>Race Condition</code>을 예방하기 위한 방법으로 <code>Mutex</code>가 있는데, 그렇게 되면 모든 객체에 <code>Mutex</code>를 적용해야 한다는 뜻이 된다.
이는 굉장히 비효율적인 방식이다.</p>
<p>그렇기 때문에 파이썬에서는 하나의 쓰레드가 인터프리터를 실행하고 있으면 다른 쓰레드는 실행할 수 없도록 인터프리터에 락을 건다. 
이것이 바로 GIL이다.</p>
<h3 id="병렬로-실행하려면-어떻게-해야-할까">병렬로 실행하려면 어떻게 해야 할까?</h3>
<p>가장 간단한 방법은 <strong>멀티 프로세싱</strong>이다.
멀티 프로세싱은 멀티 쓰레딩과 다르게 프로세스간 자원을 공유하지 않는다.
각각의 프로세스가 독립된 메모리를 사용하기 때문에 <code>Race Condition</code>으로 인한 문제가 발생하지 않는다.
하지만 메모리를 많이 소모한다는 단점이 있다.</p>
]]></description>
        </item>
    </channel>
</rss>