<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>brighten_the_way.log</title>
        <link>https://velog.io/</link>
        <description>Hello, World</description>
        <lastBuildDate>Wed, 28 Apr 2021 11:28:35 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>brighten_the_way.log</title>
            <url>https://images.velog.io/images/brighten_the_way/profile/c7f0e4b8-1501-4911-b84e-257c2ee1e1ab/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. brighten_the_way.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/brighten_the_way" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[콜백 함수]]></title>
            <link>https://velog.io/@brighten_the_way/%EC%BD%9C%EB%B0%B1-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@brighten_the_way/%EC%BD%9C%EB%B0%B1-%ED%95%A8%EC%88%98</guid>
            <pubDate>Wed, 28 Apr 2021 11:28:35 GMT</pubDate>
            <description><![CDATA[<h1 id="01-콜백-함수">01. 콜백 함수</h1>
<p>콜백 함수(callback function)은 다른 코드의 인자로 넘겨주는 함수를 말합니다.</p>
<blockquote>
<p>어떤 함수 A를 호출하면서 특정 조건일때 함수 B를 수행하라</p>
</blockquote>
<p>라고 한다면, B함수를 호출하는 제어권을 A함수에게 넘겨주었다고 생각할 수 있습니다.
콜백 함수는 다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로서 해당 함수의 제어권을 다른 코드에 넘겨준 것입니다.</p>
<h1 id="02-제어권">02. 제어권</h1>
<h3 id="1-호출-시점">1. 호출 시점</h3>
<pre><code class="language-js">setTimeout(function(){ alert(&quot;Hello&quot;); }, 3000);</code></pre>
<p>위와 같은 함수가 있다고 가정해보겠습니다.</p>
<ul>
<li>setTimeout은 첫번째 인자로 함수를 넘겨 받습니다.</li>
<li>해당 코드는 3000ms를 기다린 후 Hello를 출력합니다.</li>
</ul>
<p>setTimeout()을 호출하는 것은 사용자입니다. 하지만 setTimeout()에 넘겨준 함수를 호출하는 것은 setTimeout()이 되는 것이며 제어권 또한 setTimeout()이 가집니다.</p>
<h3 id="2-인자">2. 인자</h3>
<p>콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수를 호출할 때 인자에 어떤 값들을 어떤 순서로 넘길것인지를 제어하는 제어권을 갖고 있는 것이 됩니다.</p>
<h3 id="3-this">3. this</h3>
<p>콜백 함수도 결국은 함수이기 때문에 기본적으로 this에는 전역객체를 참조합니다. 다만 콜백 함수에 별도의 this가 될 대상을 넘기면 콜백 함수는 해당 값을 참조 하게 됩니다. (3장 공부도 추가적으로 하기)</p>
<pre><code class="language-js">setTimeout(function () { console.log(this); }, 300); ---- 안넘겼으니 전역객체

[1, 2, 3, 4, 5].forEach(function (x) {
    console.log(this);
});                                                  ---- 역시나 안넘겼으니 전역객체

document.body.innerHTML += &#39;&lt;button id=&quot;a&quot;&gt; 클릭 &lt;/button&gt;&#39;;
document.body.querySelector(&#39;#a&#39;).addEventListner(&#39;click&#39;, function (e) {
  console.log(this, e);                              ---- 콜백함수를 호출 할 때 첫번째 인자에 &#39;addEventListener&#39; 메서드의 this를 그대로 넘기기 때문에 HTML 요소를 가리킴.
});</code></pre>
<h1 id="03-콜백-함수는-함수다">03. 콜백 함수는 함수다</h1>
<p>콜백 함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는** 메서드가 아닌 함수**로서 호출 된다.</p>
<pre><code class="language-js">var obj = {
  vals: [1, 2, 3],
  logValues: function(v, i) {
    console.log(this, v, i);
  }
}

obj.logValues() // { vals: [1, 2, 3], logValues: f } 1 2
[4, 5, 6].forEach(obj.logValues);  // 전역객체 4 0 , 전역객체 5 1, 전역객체 6 2</code></pre>
<p>우리가 <code>obj.logValues(1, 2)</code>에서 호출한 것은 <code>obj</code>의 메서드이기 때문에 this는 객체를 가리키고, <code>obj.logValues</code>로 호출한 것은 메서드가 아닌 함수 그 자체이기 때문에, <code>obj</code>와는 직접적인 연관이 없어졌습니다. 따라서, this는 전역객체를 바라보게 됩니다.</p>
<h1 id="04-콜백-함수-내부의-this에-다른-값-바인딩하기">04. 콜백 함수 내부의 this에 다른 값 바인딩하기</h1>
<p>객체의 메서드를 콜백 함수로 전달하더라도 이는 함수로 호출되기 때문에 해당 객체를 this로 바라볼 수가 없습니다.
위 문제를 해결하기 위해서 this를 다른 변수에 담아서 콜백 함수로 활용할 함수에 this 대신 그 변수를 사용하고, 이를 클로저로 만드는 방식을 사용하고 있었습니다.</p>
<pre><code class="language-js">var obj1 = {
  name: &#39;obj1&#39;,
  func: function() {
    var self = this;
    return function() {
      console.log(self.name);
    };
  },
};

var callback = obj1.func();
setTimeout(callback, 1000); // 1초</code></pre>
<p>해당 함수의 <code>self</code>에다 <code>this</code>를 묶어줬으니, 이제부터 이 함수에서 호출하는 this도 <code>obj1</code> 객체가 된 것입니다.</p>
<p>콜백 함수 내부에서 this를 사용하지 않으려면 다음과 같이 할 수 있습니다.</p>
<pre><code class="language-js">var obj1 = {
  name: &#39;obj1&#39;,
  func: function() {
    console.log(obj1.name);
  }
};

setTimeout(obj1.func, 1000);</code></pre>
<p>여기서는 <code>this</code>를 활용해 다양한 상황에 재활용할 수 없게 되어버렸습니다. 여러 시도 후에 ES5부터는 <code>bind 메서드</code>가 탄생했습니다.</p>
<pre><code class="language-js">var obj1 = {
  name: &#39;obj1&#39;,
  func: function () {
    console.log(this.name);
  }
};
setTimeout(obj1.func.bind(obj1), 1000);

var obj2 = { name: &#39;obj2&#39; };
setTimeout(obj1.func.bind(obj2), 1500);</code></pre>
<p>bind 메서드를 사용하면 코드가 훨씬 간결해지고, 그 의미도 명확하게 다가옵니다.</p>
<h1 id="05-콜백-지옥과-비동기-제어">05. 콜백 지옥과 비동기 제어</h1>
<p>콜백 지옥은 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기가 중복해서 엄청나게 많아지는 것을 말합니다.</p>
<pre><code class="language-js">setTimeout(() =&gt; {
  setTimeout(() =&gt; {
    setTimeout(() =&gt; {
      // 이런식으로 콜백함수 안에 다시 콜백함수
    }, 1000)
  }, 1000)
}, 1000);</code></pre>
<p>주로 비동기적인 작업을 수행하기 위해 나타나는 형태입니다. 여기서 동기와 비동기를 짚어보겠습니다.</p>
<ul>
<li>동기(synchronous)적인 코드: 현재 실행 중인 코드가 완료된 후에야 다음 코드를 실행하는 코드</li>
<li>비동기(asynchronous)적인 코드: 현재 실행 중인 코드의 완료 여부와 무관하게 즉시 다음코드로 넘어가는 코드</li>
</ul>
<p><strong>별도의 요청, 실행 대기, 보류 등과 관련된 코드는 비동기적인 코드</strong>라 볼 수 있다.
이를 처리하기 위한 시도가 버전별로 많이 이루어졌는데, ES6에서는 Promise, Generator 등이 도입되었고, ES2018에서는 async/await가 도입되었습니다.</p>
<h4 id="promise">Promise</h4>
<p>ES6에서 추가된 후, 현재 많이 사용되고 있는 <code>Promise</code> 에 대해 먼저 알아보겠습니다.</p>
<pre><code class="language-js">new Promise((resolve, reject) =&gt; {
  setTimeout(() =&gt; {
    resolve(true);
  }, 1000);
}).then((isOk) =&gt; {
  setTimeout(() =&gt; {
    resolve(isOk);
  }, 1000);
}).catch((err) =&gt; {
  console.error(&quot;ERROR: &quot;, err);
});</code></pre>
<p>내부에 resolve, reject 함수를 호출하는 구문이 있는데, 둘 중 하나가 실행되기 전까지는 다음(then)이나 오류(catch)구문으로 넘어가지 않습니다.일반적으로 비동기 작업이 완료될 때, 그때서야 resolve, reject를 호출해서 다음 작업을 수행하는 방식입니다.</p>
<h4 id="generator">Generator</h4>
<p>함수 뒤에 *를 이용하여 구현합니다. Generator 함수를 실행하면 Iterator가 반환되며, Iterator는 next라는 메소드를 가지고 있습니다. 이 next 메소드를 호출하면 Generator 함수 내부에서 가장 먼저 등장하는 yield에서 함수의 실행을 잠시 멈춥니다. 이후 다시 next 메서드를 호출하면 앞서 멈췄던 부분부터 시작해서 그다음에 등장하는 yield에서 함수의 실행을 멈춥니다.
비동기 작업이 완료되는 시점마다 next 메서드를 호출하는 방식을 이용합니다.</p>
<h4 id="asyncawait">async/await</h4>
<p>비동기 작업을 수행하고자 하는 함수 앞에 async를 표기하고, 함수 내부에서 실질적으로 비동기 작업이 필요한 위치마다 await를 표기하는 것으로 뒤의 내용을 Promise로 자동 전환합니다. 해당 내용이 resolve된 이후에 다음으로 진행합니다.
Promise에서 then을 사용했을 때와 비슷한 방식으로 진행됩니다.</p>
<h1 id="06-정리">06. 정리</h1>
<ol>
<li>콜백 함수는 다른 코드에 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수를 말하며 제어권은 넘겨 받은 코드는 콜백 함수를 언제 실행할 것인지, 어떤 값을 넘겨줄 것인지를 결정합니다.</li>
<li>어떤 함수에 인자로 메서드를 전달 하더라도 이는 결국 함수로서 실행합니다.</li>
<li>비동기 제어를 위해 콜백 함수를 사용하다 보면 콜백 지옥에 빠지기 쉽습니다. <code>Promise</code>, <code>Generator</code>, <code>async/await</code>등 콜백 지옥을 작성하지 않을 수 있는 방법들을 익히는 방향으로 공부해야합니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Github ssh 키 등록 후 permission denied?]]></title>
            <link>https://velog.io/@brighten_the_way/Github-ssh-%ED%82%A4-%EB%93%B1%EB%A1%9D-%ED%9B%84-permission-denied</link>
            <guid>https://velog.io/@brighten_the_way/Github-ssh-%ED%82%A4-%EB%93%B1%EB%A1%9D-%ED%9B%84-permission-denied</guid>
            <pubDate>Sun, 21 Mar 2021 14:59:01 GMT</pubDate>
            <description><![CDATA[<p>먼저, <code>ssh</code> 가 낯설고 궁금한다면 아래의 글을 한 번 참고하고 시작하기 👍
<img src="https://images.velog.io/images/brighten_the_way/post/101f33ce-a81c-4c7b-b2dc-a8483028e8bc/image.png" alt="">
<a href="https://medium.com/@jamessoun93/ssh%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94-87b58c521d6f">ssh 설명 블로그</a></p>
<p>github에 조금 더 안전한 방식으로 계정을 관리하는 방법으로 SSH를 택하기로 했다면, 우리는 github <code>my_settings &gt; SSH and GPG keys</code> 탭에서 아래 로고가 알려주는 란에서 SSH key를 등록한다.
<img src="https://images.velog.io/images/brighten_the_way/post/d9be0afc-5c88-4cb5-b4dd-16da26d5468d/image.png" alt=""></p>
<p>등록하는 절차는 매우 간단한데, 여기서부터 문제가 발생한다. 평소에도 잘 사용하던 repository에 <code>git push</code>를 시도해보자</p>
<pre><code class="language-bash">Username for &#39;https://github.com&#39;:
Password for &#39;https://soheon-lee@github.com&#39;
remote: Invalid username or password.
fatal: Authentication failed for &#39;https://github.com/...</code></pre>
<p>아마 거의 모든 레포지토리에서 유저 정보를 다시 한 번 확인하는 과정이 진행되며, 기존 username과 password를 아무리 잘 입력한다고 해도, 제대로된 인증 과정이 거쳐지지 않는다. 분명히 바르게 입력해도 진행되지 않는다. 원래 그렇다.</p>
<h3 id="ssh로-인증하기로-한-이상-더이상-https로-clone-받은-repository에-기존의-방식으로는-접근할-수-없다">ssh로 인증하기로 한 이상, 더이상 https로 clone 받은 repository에 기존의 방식으로는 접근할 수 없다.</h3>
<p>처음 레포지토리를 클론 받거나, <code>git remote</code>를 연결할 때를 다시 떠올려 보면 우리는 <code>https</code>로 접근 가능하도록 지정해두었을 확률이 높다.
<img src="https://images.velog.io/images/brighten_the_way/post/25d93823-6e37-4c67-9fa6-ca5a1ff47337/image.png" alt="">
<img src="https://images.velog.io/images/brighten_the_way/post/6f75732d-90ab-44c9-8227-137e019a4800/image.png" alt=""></p>
<p>따라서, https로 접근하기로 지정한 레포지토리에는, ssh 키를 등록하고 ssh를 이용기로한 이상 더이상 접근할 수가 없게 되는 것이다.
이 때, 두가지 해결 방법이 있다.</p>
<h4 id="1-ssh-방법으로-다시-repository-clone-받기">1. <code>ssh</code> 방법으로 다시 repository clone 받기</h4>
<p>다시 클론 받으면 된다. 그러나 push를 하기 위한 commit들이 이미 있는 상태에서는, 이 방법이 그렇게 좋은 방법이라고는 할 수 없다.</p>
<h4 id="2-검색하기--how-to-change-git-config-from-https-to-ssh">2. 검색하기 : how to change git config from https to ssh</h4>
<p>가장 먼저 나오는 document는 github 공식 document인데,
git remote의 url을 ssh 버전으로 변경해주면 된다.
<code>$ git remote set-url origin git@github.com:USERNAME/REPOSITORY.git</code>
현재 url의 형태는 아래와 같을 것이다.</p>
<pre><code>git remote -v
&gt; https://github.com/USERNAME/REPOSITORY.git</code></pre><p>이를 위 명령어를 이용하여 변경해준다. 변경 후 다시 한 번 확인해본다면,</p>
<pre><code>git remote -v
&gt; origin git@github.com:USERNAME/REPOSITORY.git (fetch)
&gt; origin git@github.com:USERNAME/REPOSITORY.git (push)</code></pre><p>형태로 변경되어 있는 것을 확인할 수 있다.</p>
<blockquote>
<p>여기서, <code>git@github.com</code>은 다른 개인적인 username이 아니라 literally <code>git@github.com</code>이라고 작성해야한다.</p>
</blockquote>
<p>이렇게, git remote url을 https형식에서 ssh형식으로 변경해둔다면, 이제는 repository에 정상적으로 접근할 수 있고 아무 무리 없이 push 할 수 있다.</p>
<blockquote>
<p>기존에 사용하고 있던 repository가 있던 상태에서 SSH key를 등록했다면, 지금까지 사용하고 있던 모든 repository에서 <code>git remote set-url origin~~</code> 을 진행해주어야 한다.</p>
</blockquote>
<h3 id="참고">참고</h3>
<p><a href="https://docs.github.com/en/github/using-git/changing-a-remotes-url">https://docs.github.com/en/github/using-git/changing-a-remotes-url</a></p>
<h1 id="마치며">마치며</h1>
<p>기존 통신 방식을 여러개 알고 있다고 생각하면서도, 막상 방식을 변경하고 나니 그와 연관되어있던 다른 기능들에 변경 사항을 적용할 때에는 또 새롭다. 이런 새로운 상황을 맞이하고, 또 검색해서 해결해나가면서, 부가적인 개념들을 복습하는 것을 게을리 하지말자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[함수(function) 없이 코딩할 수 있을까? - 파이썬 함수에 대한 이야기]]></title>
            <link>https://velog.io/@brighten_the_way/%ED%95%A8%EC%88%98function-%EC%97%86%EC%9D%B4-%EC%BD%94%EB%94%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EC%9D%84%EA%B9%8C-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%95%A8%EC%88%98%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%EC%95%BC%EA%B8%B0</link>
            <guid>https://velog.io/@brighten_the_way/%ED%95%A8%EC%88%98function-%EC%97%86%EC%9D%B4-%EC%BD%94%EB%94%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EC%9D%84%EA%B9%8C-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%95%A8%EC%88%98%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%EC%95%BC%EA%B8%B0</guid>
            <pubDate>Sun, 07 Mar 2021 12:38:13 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>정확히 말하자면, 언어에서 기본적으로 제공해주는 메소드를 제외하고 독자적으로 만들어 사용하는 함수 없이 코딩할 수 있을까? 그래도 될까?</p>
</blockquote>
<h1 id="시작하며">시작하며</h1>
<p>프로그래밍을 처음 공부하기 시작하는 사람으로 가정하고, 공부하는 순서에 대해 한 번 되돌아보자.
우선 <code>변수</code>를 배운다. 어떤 언어인지를 떠나 보통 가장 먼저 <code>정수, 실수, 문자열을 선언하는 방법</code>을 익힌다. 파이썬을 배우는 경우 그 이후로 <code>list</code>, <code>dictionary</code>, <code>tuple</code>과 같은 자료형을 공부한다. 이 용어들이 조금 익숙해지면 보통 <code>함수(function)</code>를 배운다.</p>
<p><strong>우리가 매일 쓰는 함수는 대체 무엇인지, 왜 필요한지, 함수를 알기 전 내 코드들을 다시 한 번 보며 짚어보고자 한다.</strong></p>
<p>무엇을 하려는건지 몰랐어도 아래 코드를 흘낏 보면 비슷한 구조가 3,4번씩 반복되고 있다. 해당 과정은 지난 <strong>20년간</strong> <strong>한반도 근처</strong> <strong>여름</strong>의 <strong>평균 기압, 동서바람, 남북 바람</strong>의 흐름이 어떻게 변화했는지 시간에 따라 분석하여 시각화 하여 이미지 파일로 저장하는 과정이다. 굵게 처리된 부분은 실험 계획에 따라 늘 바뀔 수 있는 부분이었다.</p>
<p><em>지금 이 과정을 다시 작성한다면 전체 과정을 함수로 만들고, 관측 자료의 종료, 기간, 영역 등을 parameter로 처리했을 것이다.</em></p>
<p><img src="https://images.velog.io/images/brighten_the_way/post/444b6b65-6ce2-4f51-9666-5ce24b528acb/without_function.png" alt=""></p>
<p>실험 계획이 변경될 때마다 비슷한 실험을 여러번 해야했으므로 파일은 늘어났다. 이렇게 함수 없이 4년을 코딩했다. 이때 작성했던 내 코드의 특징을 정확하게 짚어보자면, 아래와 같다.</p>
<ul>
<li>재사용이 불가능하다. 
매 번 필요할 때마다 해당 과정을 반복해야한다.</li>
<li>독립적인 여러 절차가 동시에 얽혀있다.
관측 자료 전처리, 통계 분석, 데이터 시각화가 한 번에 이루어지고 있기 때문에 코드를 읽는 호흡이 불필요하게 길어진다.</li>
</ul>
<h1 id="함수가-만들어진-이유">함수가 만들어진 이유</h1>
<p>함수는 가장 기본적인 프로그램 구조이다. 한 번 피땀 흘려 작성한 코드가 여러 곳에서 재사용이 될 수 있도록 하는 구조이다. 복잡한 과정도 작은 단위로 분해하여 각 함수가 독립적인 역할을 하게 되고, 이는 훨씬 코딩하기 쉬운 상태로 만들어준다. 위에서 과거 코드가 보인 특징 두가지가 함수를 잘 사용해야하는 이유이다. 다시 한 번 보자.</p>
<h3 id="🔥-코드를-재사용할-수-있도록-하기">🔥 코드를 재사용할 수 있도록 하기</h3>
<p>코드의 중복을 최소화하여 재사용성을 높이</p>
<h3 id="🔥-독립적인-작업을-수행하는-단위-만들기">🔥 독립적인 작업을 수행하는 단위 만들기</h3>
<p>왜 함수를 사용하는가?</p>
<ol>
<li><p>코드 재사용성을 높이고 중복을 최소화한다.
 가장 기본적인 &#39;분해&#39; 도구다. 하나의 작업에 대하여 한 곳에서 코딩하고 여러 곳에서 활용할 수 있도록 해주기 때문이다.</p>
</li>
<li><p>절차적 분해
 한 번에 전체 작업 절차를 구현하는 것보다, 서로 간에 독립적인 더 작은 작업들을 ㄱ현하는 것이 더 쉬운 일이다. 일반적으로 함수는 &#39;절차&#39;와 관련된 것으로, 무엇을 위해 그 일을 하는가보다 무엇을 어떻게 하는가와 관련된 것이다.</p>
</li>
</ol>
<h1 id="파이썬-함수의-속성">파이썬 함수의 속성</h1>
<p>가장 기본적인 형태의 함수를 한 번 만들어보자.</p>
<pre><code class="language-python">def analyze_data():
    pass</code></pre>
<p>이렇게 생성된 함수는 기본적으로 35개의 속성과 built-in 메소드를 가지고 있다 <code>dir()</code> 함수는 해당 객체가 가지고 있는 속성과 메소드를 모두 보여준다. 물론 다른 속성들도 추가해줄 수 있으나, built-in으로 제공되는 속성과 메소드를 먼저 확인해보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; dir(analyze_data)
[&#39;__annotations__&#39;, &#39;__call__&#39;, &#39;__class__&#39;, &#39;__closure__&#39;, &#39;__code__&#39;, &#39;__defaults__&#39;, 
&#39;__delattr__&#39;, &#39;__dict__&#39;, &#39;__dir__&#39;, &#39;__doc__&#39;, &#39;__eq__&#39;, &#39;__format__&#39;, &#39;__ge__&#39;, &#39;__get__&#39;, 
&#39;__getattribute__&#39;, &#39;__globals__&#39;, &#39;__gt__&#39;, &#39;__hash__&#39;, &#39;__init__&#39;, &#39;__init_subclass__&#39;, 
&#39;__kwdefaults__&#39;, &#39;__le__&#39;, &#39;__lt__&#39;, &#39;__module__&#39;, &#39;__name__&#39;, &#39;__ne__&#39;, &#39;__new__&#39;, 
&#39;__qualname__&#39;, &#39;__reduce__&#39;, &#39;__reduce_ex__&#39;, &#39;__repr__&#39;, &#39;__setattr__&#39;, &#39;__sizeof__&#39;, 
&#39;__str__&#39;, &#39;__subclasshook__&#39;]</code></pre>
<h2 id="built-in-attributes">Built-in attributes</h2>
<p>7개의 파이썬 built-in 속성들을 소개하고자 한다. 몰라도 큰 문제는 없었지만, 한 번 알게 된 이상 자주 활용할 수 있는 속성들이다. 예시 함수는 아래와 같다.
<img src="https://images.velog.io/images/brighten_the_way/post/e7480982-183d-401b-9551-685e5f1e702e/image.png" alt=""></p>
<h4 id="1-annotations--doc--defaults">1. annotations &amp; doc &amp; defaults</h4>
<p>세 속성은 모두 선언된 함수를 보다 쉽게 이해할 수 있도록 하는 역할을 한다. </p>
<ul>
<li><code>__annotations__</code> : 함수를 선언할 때 지정하는 <code>parameter</code>에 덧붙인 부가 설명에 접근 할 수 있고 예시 코드 3, 4, 5번 줄과 같이 지정한다.</li>
<li><code>__defaults__</code> : 마찬가지로, 함수를 선언할 때 지정하는 parameter에 할당해 둔 <code>__default arguments__</code>에 접근할 수 있는 속성으로, 예시 코드 5번 라인 <code>37.0</code>을 일컫는다.</li>
<li><code>__doc__</code>: 함수 선언시 작성한 docstring 내용을 확인할 때 사용하는 속성이다.</li>
</ul>
<p>예시 함수의 세가지 속성을 부르면 아래와 같이 나타난다.</p>
<p><img src="https://images.velog.io/images/brighten_the_way/post/e590be68-0023-4d4c-bbfc-648d98b6c3e7/image.png" alt=""></p>
<p>list를 정렬할 때 자주 사용하는 <code>sorted()</code> 메소드의 <code>__doc__</code>를 확인해보자.
<img src="https://images.velog.io/images/brighten_the_way/post/72d0a9ee-d342-46de-a6b7-02023dc8f793/image.png" alt="">
내가 사용하는 함수가 애초에 어떤 이유로 만들어졌는지 파악하기에 수월하다. 그러나 그 기능을 애초에 전혀 모르고 보았을 때에 바로 알기는 어려우므로, 구글링으로 해당 함수의 대략적인 동작기작을 알고 난 뒤에, 종종 까먹었을 때 확인하기에 좋다고 생각한다.</p>
<h4 id="2-class">2. class</h4>
<p>특정 인스턴스가 어떤 객체인가를 알려주는 속성으로, 파이썬 built-in 함수인 <code>type()</code>과 같은 역할을 한다.</p>
<pre><code class="language-python">def analyze_data():
    pass

&gt;&gt;&gt; analyze_data.__class__
&lt;class &#39;function&#39;&gt;</code></pre>
<p>이 속성은 함수가 아닌 다른 객체에서도 원활히 동작한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = 1
&gt;&gt;&gt; a.__class__
&lt;class &#39;int&#39;&gt;</code></pre>
<p>그러나 타이핑이 길어 <code>type()</code>을 더 많이 사용할 것 같다.</p>
<h4 id="3-module--name--qualname">3. module &amp; name &amp; qualname</h4>
<p>속성 이름이 매우 직관적이다.</p>
<ul>
<li><code>__module__</code>: 함수가 포함되어 있는 모듈, 즉 파일의 이름을 알려준다. 어디서 import 한 함수인지 알고 싶을 때 용이하게 사용할 수 있다.</li>
<li><code>__name__</code>: 해당 함수의 이름을 알려주는 속성. 개인적으로 사용 의도가 의아했던 속성이다.
그러나 함수를 다른 변수에 할당해서 사용하거나 <code>import pandas as pd</code> 와 같이 축약된 이름으로 객체의 이름을 변경하여 사용할 때, 원래 이름을 알아내기에 매우 편리할 것이다.
또한, <code>if __name__ == __main__</code> 와 같은 조건에서 사용된다. 터미널에서 바로 사용되는 모듈과 다른 모듈에서 <code>import</code> 되어 사용되는 모듈에 대해서는 따로 기록하도록 한다.</li>
<li><code>__qualname__</code>: <code>__name__</code>과 마찬가지로 함수의 이름을 표현한다. <code>__name__</code>과 달리 클래스나 함수가 중첩되어 있을 때, 중첩 관계 (<code>path</code>) 까지 보여주기 때문에 같은 이름의 메소드가 있어도 디버깅을 조금 더 수월하게 해주는 장점이 있다.
아직 사용해본 적이 없는 속성이라, <code>__name__</code>과의 비교 후, 직접 사용해보기로 한다.
<img src="https://images.velog.io/images/brighten_the_way/post/8ceaedd0-ba48-4215-9ae0-1b9f5d8c4ba3/image.png" alt="">
이름을 비교해보기 위하여 fun 이라는 변수에 원본 함수를 할당해두었다. 현재와 같은 상황에서는 <code>__name__</code>과 <code>__qualname__</code>이 같다.</li>
</ul>
<hr>
<h2 id="built-in-methods">Built-in methods</h2>
<p>우리에게 필요한 속성을들 임의로 추가할 수는 없을까? 물론 있다. 파이썬이 함수를 사용할 때 제공해주는 많은 built-in 메소드를 확인해보고, 그 메소드 가운에 하나인 <code>__setattr__</code>를 이용해 속성을 추가해보자.</p>
<h4 id="1-setattr-getattribute-delattr">1. setattr, getattribute, delattr</h4>
<p>세 메소드 또한 이름이 직관적이라는 사실이 가장 마음에 든다.</p>
<ul>
<li><code>__setattr__</code>: 함수 인스턴스에 속성을 추가해줄 때에 사용하는 메소드이다.</li>
<li><code>__getattribute__</code>: 추가해준 속성에 접근할 때 사용하는 메소드이다.</li>
<li><code>__delattr__</code>: 추가했던 속성을 제거할 때 사용하는 메소드이다.<pre><code class="language-python">def function1():
  pass
</code></pre>
</li>
</ul>
<blockquote>
<blockquote>
<blockquote>
<p>function1.<strong>setattr</strong>(&#39;nickname&#39;, &#39;function_one&#39;)
function1.<strong>getattribute</strong>(&#39;nickname&#39;)
function_one
function1.<strong>delattr</strong>(&#39;nickname&#39;) # 제거
function1.<strong>getattribute</strong>(&#39;nickname&#39;) # 제거한 속성에 다시 접근</p>
</blockquote>
</blockquote>
</blockquote>
<p>Traceback (most recent call last):
  File &quot;<stdin>&quot;, line 1, in <module>
AttributeError: &#39;function&#39; object has no attribute &#39;c&#39; # 더이상 존재하지 않는 속성이므로 Attribute 에러 발생</p>
<pre><code>이를 사용하다보면 자연스롭게 일반적으로 객체에 속성을 지정하는 방법이 떠오를 것이다.
```python
&gt;&gt;&gt; function1.nickname = &#39;function_one&#39;
&gt;&gt;&gt; function1.nickname
&#39;function_one&#39;</code></pre><p>사실 위와 같은 역할이다. <code>function1.nickname = &#39;function_one&#39;</code>이라 할당할 때에 <code>__setattr__</code>메소드가 호출되기 때문이다.</p>
<h4 id="2-str-repr">2. str, repr</h4>
<p>파이썬 장고로 개발하는 것이 익숙해진 나에게 가장 친숙한 메소드 가운데 하나가 <code>__str__</code>이다. 해당 객체가 호출될 때 어떻게 사용자에게 표현될 것인가를 결정하는 메소드들인데, 함수를 예시로 들기보다는 다른 객체들을 사용하여 비교하는 것이 보다 좋다고 판단했다.
<code>str</code>과 <code>repr</code>은 모두 객체를 문자열 형태로 표현해주는 역할을 한다. 사람이 눈으로 보고 어떤 객체인지 읽어내야하기 때문이다.</p>
<p><img src="https://images.velog.io/images/brighten_the_way/post/4390a241-4152-449e-ae61-7e9174c0cbff/image.png" alt="">
자주 사용하는 객체인 <code>datetime</code>객체를 한 번 보자. 지금 현재 시각을 <code>now</code>라는 변수에 담았는데, <code>__str__()</code> 메소드는 보다 사람이 알기에 친숙하고, 알아보기 쉬운 상태로 표현하고, <code>__repr__()</code>메소드는 그렇게 친절한 편은 아니다.</p>
<table>
<thead>
<tr>
<th>str()</th>
<th>repr()</th>
</tr>
</thead>
<tbody><tr>
<td>Make object readable</td>
<td>Required code that reproduces object</td>
</tr>
<tr>
<td>Generate output to end user</td>
<td>Generate output for developer</td>
</tr>
<tr>
<td>많은 사람들이 이런 기준을 가지고 str()과 repr()을 사용하고 있다. 그리고 또 한가지, str()과 repr() 과 같이 함수를 호출하는 방법으로 사용하는 것이 좋고 직접적으로 <code>__str__()</code>에 접근하는 것은 추천하지 않는다.</td>
<td></td>
</tr>
</tbody></table>
<h1 id="마치며">마치며</h1>
<p>함수를 숨 쉬듯이 사용하고 있다. 위키백과에 따르면 최초의 컴퓨터들과 마이크로프로세서들은 단일 함수 호출 명령어가 없었다고 한다. 함수를 구현할 수는 있었지만, 거의 사용하지 않았다고 보면 된다. 많은 불편함이 쌓여서 함수가 개발되었을테다. 좋은 도구라고 하여도 제대로 사용하지 못하면 그 역할을 제대로 하기 어렵다. 앞으로도 재사용 가능하고 독립적인 기능을 하는 작은 단위로 코드를 잘 분리하여 보다 함수를 잘 활용하고자 다짐한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[10개월차 코딩 부트캠프 멘토, 2020년 회고록]]></title>
            <link>https://velog.io/@brighten_the_way/10%EA%B0%9C%EC%9B%94%EC%B0%A8-%EC%BD%94%EB%94%A9-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%98%ED%86%A0-2020%EB%85%84-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@brighten_the_way/10%EA%B0%9C%EC%9B%94%EC%B0%A8-%EC%BD%94%EB%94%A9-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%A9%98%ED%86%A0-2020%EB%85%84-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Sat, 13 Feb 2021 19:51:09 GMT</pubDate>
            <description><![CDATA[<p>2020년은 누군가에게 멘토링을 하는 시간으로 가득 채웠다. 하루가 다르게 성장하는 스타트업에서, 매일이 순식간에 지나가는 부트캠프에서, 나는 어떻게 한 해를 보내었는가를 돌아본다.</p>
<h2 id="누가-코딩-부트캠프에-오는걸까">누가 코딩 부트캠프에 오는걸까</h2>
<blockquote>
<p>그들은 진심이고, 그 옆에서 같이 일을 하고 있는 나 또한 어느 한 순간도 진심이지 않을 수 없다.</p>
</blockquote>
<p>간혹 코딩 한 번 배워보고 싶어서 등록하려 합니다. 라고 말씀하시는 분도 있다. 정말 간혹.
그러나 수강생 분들 대부분은 그간 내가 해오던 것을 잠시 덮어두고 커리어를 바꾸고자 위코드의 문을 두드린다.
웃으면서 오는 분도 있고, 울지 못해 쓴 웃음 지으면서 오는 분도 있다. 현실이 답답해 잘 다니던 직장을 시원하게 그만두고 여행을 떠나는 것이 멋일 수도 있지만, 그런 결정은 현실의 모든 사람에게 주어지는 선택권은 아니다. 잘 다니던 직장을 그만두고, 다니던 학교에서 펜을 내려두고 부트캠프에 3개월이라는 시간을 투자한다는 것은 쉽게 내릴 수 있는 결정이 절대 아니다. 자신의 삶을 정말로 바꾸고 싶어서 큰 마음 먹고 내리는 결정이고, 이들은 진심이다. 이들이 처음 상담 신청을 남길 때의 마음이 어떤지, 처음 상담할 때의 두려움이 무엇인지, 기대감이 무엇인지 나 또한 정말이지 잘 알고 있다. 다들 그 어느 때보다 걱정되고, 진심이고, 한 편으론 설렌다. 그 감정의 무게를 알기에 그 옆에서 같이 일을 하며 돕고 있는 나는 어느 한 순간도 진심이지 않을 수 없다.</p>
<p>같이 설레고
같이 신나고
같이 걱정되고
같이 극복한다</p>
<hr>
<h2 id="나는-어떤-일을-하는가">나는 어떤 일을 하는가</h2>
<p>첫 출근을 하던 2020년 4월 20일로부터 약 열 달이 지난 지금, <strong>내가 어떤 일을 하고 있는가</strong>와 <strong>일을 왜 하고 있는가</strong>에 대한 질문을 처음으로 던져본다. 조금 더 일찍 던졌어야 하는가 싶다가도, 그땐 답이 나오지 않았으리라.</p>
<p>이 글의 초고를 쓰던 몇주 전, 한 <a href="https://biz.chosun.com/site/data/html_dir/2020/08/11/2020081104499.html">칼럼</a>의 첫 문장이 인상깊어 스크랩해두었다.</p>
<blockquote>
<p>유재석은 &#39;위대한 코치&#39; 김태호 PD의 추임새를 거절하지 않는 것을 통해 자기 잠재력을 극한으로 끌어올린다. &quot;즐길 수 있는 정도의 고통을 주고 싶다&quot;는 김태호의 자극에 신나게 자기를 갈아 넣는 것이다.</p>
</blockquote>
<p>사람의 잠재력을 끌어올리는 것. 유재석을 대하는 김태호 PD의 모습을 떠올리자마자, 위코드 멘토가 떠올랐다. 내가 정의하기에 나는, 사람의 잠재력을 끌어올리는 일을 하고 있다. 위코드를 찾아온 사람의 의지와 꿈을 연료로 그들의 잠재력을 폭발시키는 것이 내가 하는 첫번째 일이다. 구글에 <strong>교육</strong>을 검색해본다. </p>
<blockquote>
<p><strong>교육</strong> : 사회 생활에 필요한 지식과 기술을 가르치고, <strong>인간의 잠재 능력을 일깨워</strong> 훌륭한 자질, 원만한 인격을 갖도록 이끌어 주는 일&#39;</p>
</blockquote>
<p>참 신기하다. 내가 정말로 교육을 하고 있었구나. 나는 정말로 멘토로서 내 옆 사람을 이끌고 있었다. 아이러니하게도 이 때부터 내 생각의 방향이 조금 달라졌다. 나는 개발을, 코딩을 가르치고 있는 것이 아니었다. 나는 이 사람이 스스로 더 공부할 수 있도록, 개발 학습 방법이 몸에 익을 수 있도록 잠재력을 길러내는 데에 더 집중을 하게 되었다. 김태호 PD는 절대 유재석에게 남에게 웃음을 주는 방법을 직접 가르쳐주지 않았을테다. 유재석의 노력이 빛을 발할 수 있도록 환경을 제공하고, 코칭을 하고, 멘토로서 방향을 제시하고, 동시에 PD로서 해야하는 일에 전력을 기울이며 스스로도 굉장히 많이 성장했을테다. </p>
<h3 id="그럼-나는-정말로-뭘했을까">그럼 나는 정말로 뭘했을까?</h3>
<h4 id="📍-2분기---몸으로-부딪혔던-멘토링의-시작">📍 2분기 - 몸으로 부딪혔던 멘토링의 시작</h4>
<blockquote>
<p>어떻게 시작해야할 지 몰라서 일단 몸으로 최대한 많이, 최대한 오래 부딪혀봤다.</p>
</blockquote>
<ul>
<li><p>입사 초반에는 막 7기가 프로젝트를 진행 중이었고, 8기가 시작되기 며칠 전이었다. 내가 할 수 있는 것과 해야하는 것 중에 가장 중요한 것은 수강생분들과 빠른 시간안에 친해지고 이 커뮤니티에 녹아드는 것이었다. 내게 첫번째로 주어진 업무는 크게 하나였는데, 현재 진행되고 있는 커리큘럼에서 보완해야할 사항을 찾아서 수정하는 것이었다. 믿기진 않지만, 사실 처음에는 고칠 것이 없다고 생각했다. 지금 다시 묻는다면 고쳐야 할 것들을 쏟아내겠지만 다시 생각해도 그때는 완벽해보였다.</p>
</li>
<li><p>그와 동시에 입사 2주차 월요일에 가장 진행이 더디고, 어려워하는 수강생분이 많았던 7기 프로젝트팀, <a href="https://velog.io/@bong2030/1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%9D%B4%EC%A0%9C%EC%84%9C%EC%95%BC-%EC%8D%A8%EB%B3%B4%EB%8A%94-%ED%9A%8C%EA%B3%A0%EB%A1%9D">형님의 파우치 팀</a>과 롤렉스팀 프로젝트에 긴급 투입되었다. 그때의 내가 정말 뭘 알긴 했던건지 모르겠다. 수강생분 이름만 빠르게 외우고 10A에서 3~4시간씩을 달렸던게 기억난다. 그렇게 힘든 시간 보냈던 분들이 지금은 취업해서 어엿한 백엔드 개발자로 사회에서 가치 창출을 해내고 있다. 정말 신기하고도 감사한 일이다. 봉현님, 정인님 정말 응원합니다. 이때 주어진 사내 개발 모델링에도 들어가서 열심히 마이그레이션도 공부했다.</p>
</li>
<li><p>8기부터 긴장이 조금 풀리고 나서야 멘토로서 고민해야할 것들이 하나씩 보이기 시작했다. 끝없이 늦어지는 수강생의 진도는 어떻게 할 것인가. 이 사람이 보고 공부해야할 복습 컨텐츠는 어떻게 해야하는가 (이때 정말 지훈님과 상록님의 영상이 만들어지는 속도가 엄청났다). 친구처럼 편하게 같이 프로젝트에 대해 고민하면서도, 수강생이 사고하는 깊이를 깊게 해주려면 어떻게 대화를 이어나가야 하는지도 고민했던 시기이다. 도움 많이 주신 시환님, 미선님, 승호님, 혜랑님 ...</p>
</li>
<li><p>9기는 역대급으로 백엔드 수강생이 많았던 기수다. 21명. 이 시기 정말 재밌었는데 진짜 너무 바빴어서 기억이 안난다. 눈 뜨면 선릉이었고, 눈 감으면 다시 아침이고 선릉이었다. 다시 하라고 하면 할 수 있을까. 몸이 부서질 것 같았던 기억은 난다. 20명의 백엔드 분들과 10A에서, 16A에서 열심히 모델링하고, conflict 해결하라고 마지막 다잉메세지를 남기고 마지막 전철 때문에 뛰고, 전철에서 리뷰하고, 10층과 7층으로 분리된 시기라 이동하면서 잃어버린 충전기가 두 개... 내 충전기들 다 어디갔니... </p>
</li>
</ul>
<h4 id="📍-3분기---머리-싸매고-컨텐츠-보완--커리큘럼-변경">📍 3분기 - 머리 싸매고 컨텐츠 보완 / 커리큘럼 변경</h4>
<blockquote>
<p>코로나.. 코군분투 하면서 지켜내고 만들어낸 내 사랑 백엔드 커리큘럼 ver.2</p>
</blockquote>
<ul>
<li><p>커리큘럼을 재정비하고, 이전 과제와 다음 과제 사이의 연관성을 높이기 위해 첫번째 타겟으로 위스타그램을 선정했다. 10기가 시작되고 얼마 후, 구두로 전달하고, 구두로 확인하던 <code>sign up, sign in</code> 과제를 모두 github에서 진행될 수 있도록 mission을 list up 했다. 
<img src="https://images.velog.io/images/brighten_the_way/post/02111f7d-f64d-4e53-9625-99ef9cb28c12/image.png" alt=""> 프론트엔드 과제를 잘 정비해둔 준식님 승현님 덕에 벤치마킹 수월하게 할 수 있어고, 백엔드 사정대로 바꾸는 데에만 꼬박 한 달이 걸렸다. 이 시기의 나를 정말 칭찬한다. 고생했어. 가능했던 이유는 때마침 와주신 병민님이 우리 기적의 수미님을 잘 케어해주신 덕이었다.</p>
</li>
<li><p>11기부터는 제대로 위스타그램을 github에서 진행했는데, 필수 과제가 일찍 끝난 분들이 이후로 추가 학습을 할 수 있도록 mission을 굉장히 세분화해서 추가했다. 추가 학습 미션은 세세한 가이드가 없었는데도, 필수 구현을 제대로 한 분들은 자기만의 사고 과정을 토대로 나름의 로직을 가지고 구현하는 점을 확인했다. 역시, 내적 동기부여가 지속적으로 되는 사람에게는 기초가 잡혀있다는 가정 하에 응용과제는 자율에 맡기는 것이 좋음을 확인한 과정이었다. <strong>초반 개념을 잘 잡아주는 것과, 끝없이 동기부여를 해주는 것이 나의 역할</strong> 개발하는 시간이 적은 것에 대한 초조함을 느끼는 시기이기도 했다. 그래서 공부를 더 시작했고, 코드 리뷰를 하면서 배우는 점이 정말 많다는 것을 다시금 깨우치며 극복하는 시기이기도 했다. <a href="https://blog.logi-spot.com/%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0%EC%9D%98-%EC%A7%84%EC%A7%9C-%EB%AA%A9%EC%A0%81%EC%9D%80-%EB%94%B0%EB%A1%9C%EC%9E%88%EB%8B%A4/">코드리뷰의 진짜 목적은 따로있다.</a> 라는 글이 도움이 많이 됐다.</p>
</li>
<li><p>12기 개강 얼마 후, 코로나가 심해져 정부 방역지침에 따라 온라인으로 과정을 진행하게 되면서 컨텐츠 보완에도 어려움이 생겼었지만, 위기를 기회로, 온라인에 최적화된 수업 자료를 생산하면서 더욱 정비된 백엔드 커리큘럼이 완성됐다. 이 때, 병민님, 준식님, 준님과 회의 정말 많이 하면서 공통 세션 순서도 같이 바꾸었다. 병민님 덕에 Django official tutorial로만 진행되던 과정을 CRUD1, CRUD2로 재정비했다. 될까 싶었지만 도전하는 마음으로 데이터베이스와 크롤링에 거꾸로 수업을 도입해보았다. 비대면 과정 진행후 회고 미팅에서, 극복해야할 포인트와, 오히려 비대면이어서 발전에 도움이 되었던 요소들을 정리하여 공유했고, 그 때의 회의 내용들은 지금 업무를 진행하는 데에 있어서도 큰 도움이 되곤한다.</p>
</li>
<li><p>다행히 코로나 여파를 앞뒤로 벗어난 13기부터는 DB모델링을 프/백 공통세션으로 진행하자고 제안하였고, 뭇 프론트 수강생분들의 원성 짙은 눈빛을 받았다. 한 분으로부터는 &#39;소헌님, 모델링 세션을 듣고 저는 정말 프론트구나 하고 알게됐어요. 감사해요&#39; 라는 웃지 못할 감사 인사를 들었다😂 그 분 좋은 회사에서 프론트엔드 개발자로 훨훨 날고 있으시다. 지안님... 잊을 수 없어요...
어찌됐든 이렇게 지훈님이 컴백하시기 전까지 커리큘럼 재정비를 끝내겠다는 목표는 달성되었고, 지금 보이는 아쉬운 부분은 추후 백엔드 커리큘럼 ver.3으로 보완될 것이다. 벌써 기대된다.</p>
</li>
</ul>
<h4 id="📍-4분기---업무와-학습의-효율을-높이기-위한-시간">📍 4분기 - 업무와 학습의 효율을 높이기 위한 시간</h4>
<blockquote>
<p>내 일이, 성취감으로 보상받을 수 있도록. 그 누구도 아닌 내가 인정하는 내가 될 수 있어야한다.</p>
</blockquote>
<ul>
<li><p>커리큘럼이 정리된 후, 두가지에 집중했다. 업무의 효율 증대와 수강생 학습 성취도 증가. 3개월차 설문조사 결과를 분석하다 아쉬운 부분이 몇 가지 있었는데, 3개월차에 기업협업을 매우 집중해서 열심히 진행하는 것에 비해 스스로의 성취감이 크지 않은 분들이 있는 것이었다. 준식님과 비슷한 이야기를 하다가 3개월차 기업협업 마무리도 큰 행사이니만큼 전체적으로 다른 팀들과 결과물을 공유하는 미팅 시간을 갖기로 했고, 14기에 바로 도입했다. 멘토들도 3개월차에 활동으로, 혹은 기업협업 결과물을 확인할 수 있는 시간이 되었고, 서로 수료식 전에 얼굴 보며 정말로 3개월을 마무리 하는 시간을 가질 수 있는 시간이 되어 정말 도움이 되는 시간이었다. 이 하루가 3개월 전체의 만족도에 기여하는 바가 어떨 지는 아직 정확하지 않지만, 꼭 있어야 하는 시간임에는 틀림없다.</p>
</li>
<li><p>학습 시간을 공유하는 구글캘린더는 매 기수 다르다. 해당 기수의 전체적인 진도에 따라 다르고, 그 달에 포함된 이벤트에 따라 다르기 때문에 멘토들은 매주 스케줄링을 진행한다. 매우 중요한 시간이지만 또 반복되는 일정들도 많기 때문에 스케줄 미팅에 투자되는 시간이 많다. 이때 꼭 필요한 곳에 시간과 에너지를 쓰게 하기 위해서, 중요도가 다소 떨어지는 반복 일정 추가 업무는 코드로 만들어서 엔드포인트로 호출할 수 있도록 만들었다.</p>
</li>
</ul>
<hr>
<h2 id="이-과정을-기꺼이-겪은-이유는-무엇일까">이 과정을 기꺼이 겪은 이유는 무엇일까</h2>
<h3 id="📍-개인의-성장">📍 개인의 성장</h3>
<blockquote>
<p>질량이 아무리 작을지언정, 높이 올라가면 그 위치에너지로 할 수 있는 운동은 어마어마합니다.</p>
</blockquote>
<p>김태호 PD가 유재석의 잠재력을 끌어올리는 역할이라, 위코드 멘토와 비슷한 역할인 것 같다고 했다. 무한도전을 보고 자란 세대로서, 학생이던 내 눈에 언제나 스포트라이트는 유재석이었다. 그런데 지금은, 김태호 PD가 더 눈에 자주 들어온다. 아무것도 없던 무한도전을 13년간 이끌어온 PD의 재량은 대체 얼마나 성장했을까. 나는 그런 사람이고 싶다. 아무것도 아니었던 것을 하나의 장르를 대표하도록 만드는 사람. 지난 10개월을 차분히 되돌아보며, 나는 정말로 1년만에 할 수 없을 것 같아 보이는 것들을 해냈다고 자부할 수 있다. 그리고 더 양질의 결과물을 만들어내는 사람이 되고 싶다. 자만하지 않고, 정말로 매달 자부심을 갖고 나를 인정하는 사람이 되고 싶기 때문에 매 순간 최선을 다했다. </p>
<p>아쉬운 점은 개인 블로그를 꾸준히 유지하지 못했다는 것인데, 이 회고를 기회삼아 내가 만들어내고, 내가 공부하고, 내가 부족한 점에 대해서 다시 한 번 글을 꾸준히 써야 겠다고 다짐한다.</p>
<h3 id="📍-배우고-싶은-사람은-배워야-한다">📍 배우고 싶은 사람은 배워야 한다</h3>
<blockquote>
<p>기회는 많이 배운 사람에게 주어집니다. 배움은 모든 사람에게 평등해야해요.</p>
</blockquote>
<p>나는 운이 좋아서 한국의 주입식 교육에 최적화된 성향을 가진 사람으로 태어났다고 생각한다. 선생님 말씀 잘 듣고, 가르쳐주는대로 잘 배우는 사람으로 자랐다. 운이 좋았던 것이다. 내 노력만으로 잘된 것은 아니다.</p>
<p>세상엔 당연히 많은 사람들이 있고, 각자의 사정이 있다. 학교에서 주입식으로 공부하는 것이 안 맞았던 사람, 환경이 적합하지 않았던 사람, 큰 시련이 있었던 사람, 뒤늦게 눈이 트인 사람, 하고 싶은 것을 찾아 먼 길을 돌아온 사람까지. 그 사람들이 전부 학교 교육으로 평가받고 내가 하고 싶은 것에 도전하는 데에 발목이 잡힌다는 것은 어찌보면 정말 잔인한 일이 아닐 수 없다. 우리는 원하는 것을 업으로 삼고, 그 업을 통해 삶을 영위할 권리가 있다. 또 내 삶으로 다른 인류의 삶에 공헌해야할 의무가 있다. 대학교에서 배운 거의 유일한 깨우침 두번째이다. 첫번째는 코딩이다.</p>
<p>수강생분들은 여기까지 오기 위한 과정이야 어쨌든 다음 꿈을 갖고 살아갈 목표를 찾기 위해 문을 두드린 것이다. 내가 이 두드림에 답을 찾는 과정을 도와줄 수 있다는 것은 오히려 내가 더 성장할 수 있고, 내가 더 감사할 수 있는 기회가 된다. 나는 기회의 평등을 제공하고 있다. 이건, 가끔 정말 감격스럽고, 또 매우 자주 뿌듯한 일이다. </p>
<h2 id="그래서-멘토로서-2020년을-잘-보내었는가">그래서 멘토로서 2020년을 잘 보내었는가</h2>
<p>잘 보냈다. 내년은 부족했던 점을 보완하면서 더 잘 보낼 계획이다. 돌아보니, 내가 교육을 한다는 점을 조금 부담스러워했다. 내게 있어 교육은 내가 잘 받아들인 주입식 교육의 느낌이 조금 더 컸기 때문이다. &quot;나는 개발자고. 멘토링을 하는 거지, 교육은 아니야.&quot; 라고 생각하며 책임감을 덜고 싶었을 지도 모를 일이다.</p>
<p><img src="https://images.velog.io/images/brighten_the_way/post/cb0b42f7-8fdd-499f-b77d-a2efd1863358/image.png" alt="">
팀 준식님에게서 추천받은 도서, <a href="https://www.bookjournalism.com/books/301">미래의 교육, 올린</a> 에서 뼈를 세게 얻어 맞음과 동시에 우리가 잘 해나가고 있음을 응원 받은 문장이 있다.</p>
<blockquote>
<p>세상은 자발적 동기에 의해서 학습하는 평생 학습자를 요구하는데, 교육은 아직도 시키는 것만 열심히 하는 사람을 최우선이라고 생각하는 구조에 머물러 있다.
...
학생들이 사고할 수 있는 능력을 길러주는 교육은 강의만으로는 이뤄지지 않는다.</p>
</blockquote>
<p>이 책에서 제안하는 문장들을 보며, 나는 개발자이면서 교육을 동시에 하고 있음을 요만큼도 부정하지 않게 되었다. 큰 마음 먹고 개발자의 세상에 발들인 분들이 일방적인 사고에 갇혀 내적 동기가 떨어지는 일이 없도록 꾸준히 가이드하면서 보낼 것이다. 우리와 함께 공부하는 학습 내용이 세상의 관심과 연결되어 있다는 사실과 많은 사람들이 비슷한 고민을 하고 있다는 것을 알려주기 위해 노력하면서 보낼 것이다.</p>
<p>사실상 처음으로 나를 회고해보았다. 멘토가 아닌 사람으로서의 일상도 다시 회고 하는 시간을 꼭 갖도록 해야겠다. 설 연휴에 회고록 한 편 나온 것으로 매우 알찼다.</p>
<hr>
<p>2021.02.14.Sun</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Yoyo database migrations]]></title>
            <link>https://velog.io/@brighten_the_way/Yoyo-database-migrations</link>
            <guid>https://velog.io/@brighten_the_way/Yoyo-database-migrations</guid>
            <pubDate>Sun, 12 Jul 2020 08:06:04 GMT</pubDate>
            <description><![CDATA[<p>루이비통 요요. 약 30만원.</p>
<h2 id="소개">소개</h2>
<p>마이그레이션.. 언제나 짜릿하고 매우 자주 스트레스를 받는다. 오늘은 그 이름도 귀여운 <a href="https://pypi.org/project/yoyo-migrations/">요요마이그레이션</a>에 대해 공부해본다.
간단한 마이그레이션 파일을 생성해 MYySQL 데이터베이스에 테이블을 만들어보자.</p>
<blockquote>
<p>요요(Yoyo)는 데이터베이스 스키마를 마이그레이션 해주는 도구이다. </p>
</blockquote>
<p>Migration파일 내부에는 데이터베이스에 테이블을 만들기 위한 마이그레이션 코드 (SQL or 파이썬) 가 단계별로 작성되어 있다. 예를 들어, 아래 사진과 같이.
<img src="https://images.velog.io/images/brighten_the_way/post/586bd6be-62c9-42da-a7ca-433c0e5f8b33/Screen%20Shot%202020-07-08%20at%202.48.27%20PM.png" alt="">
(오늘의 여담, 나는 처음 보는 코드에 무한히 낯을 가린다. 후... 친해지기 힘들어... 낯선 코드...)</p>
<h2 id="설치">설치</h2>
<pre><code class="language-bash">conda activate flask-graphql-bobful &lt;&lt; 설치 전에 언제나 잊지 말자 가상환경 !!

pip install yoyo-migrations</code></pre>
<p>끝!</p>
<h2 id="자-이제-시작">자, 이제 시작</h2>
<p>테이블 하나 당 migration 파일을 하나 만들기로 한다.</p>
<h4 id="1-새로운-마이그레이션-파일-생성">1. 새로운 마이그레이션 파일 생성</h4>
<p>오늘은 두가지 파일을 만들어 볼 것이다. </p>
<blockquote>
<ol>
<li><code>user_status</code> 테이블 생성 스키마</li>
<li><code>users</code> 테이블 생성 스키마</li>
</ol>
</blockquote>
<p>파일 사이에 의존성이 있기 때문에 아무 파일에도 의존하지 않는 파일 먼저 생성해야한다. 예를 들어 foreign_key 라든가 foreign_key 라든가 foreign_key 같은...</p>
<blockquote>
<p><code>user</code>데이터를 한 줄 생성하기 위해서는 <code>user_status</code>가 먼저 만들어져 있어야 하므로, 1번 파일을 먼저 만든다.</p>
</blockquote>
<pre><code class="language-bash">yoyo new . -m &quot;Create user_status table&quot;</code></pre>
<p>명령어를 실행하면 자동으로 요요 마이그레이션 파일이 생성되고, 내부에 이런 코드가 있다.</p>
<pre><code class="language-python">&quot;&quot;&quot;
Create user_status table
&quot;&quot;&quot;

from yoyo import step
__depends__ = {}

steps = [
    step(&quot;&quot;)
]</code></pre>
<h4 id="2-마이그레이션-파일-작성">2. 마이그레이션 파일 작성</h4>
<p><code>user_status</code> 테이블이기 때문에 id, status, 생성 날짜만 기입하도록 한다. 사용될 데이터로는 우선 샘플로 <code>PENDING</code>과 <code>SIGNED_UP</code> 상태만 추가해두기로 한다.</p>
<pre><code class="language-python">&quot;&quot;&quot;
Create user_status table
&quot;&quot;&quot;

from yoyo import step

__depends__ = {} &lt;------- 그 어떤 파일에도 의존하지 않는 마이그레이션!

steps = [
    step(&quot;&quot;&quot;
         CREATE TABLE user_status (
            id INT NOT NULL AUTO_INCREMENT,
            status VARCHAR(50) NOT NULL,
            created_at TIMESTAMP NOT NULL DEFAULT NOW(),
            primary key(id)
        );
    &quot;&quot;&quot;, ignore_errors=&#39;apply&#39;),
    step(&quot;&quot;&quot;
         INSERT INTO user_status (id, status)
         VALUES (1, &quot;PENDING&quot;), (2, &quot;SIGNED_UP&quot;)
    &quot;&quot;&quot;, ignore_errors=&#39;apply&#39;)
]
</code></pre>
<p>저장하고 나가면 터미널에 아래와 같은 질문이 뜬다.
<img src="https://images.velog.io/images/brighten_the_way/post/d484cb7f-1be4-45f1-9a4e-b9bc309e240e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.12.15.png" alt="">
주저 없이 <strong>yes!</strong> 
yoyo.ini 라는 이름의 configuration파일이 생성된다.</p>
<p>생성된 마이그레이션 파일 이름(<code>20200712_01_oUtFx-create-user-status-table.py</code>)이 마음에 들지 않기 때문에 (<code>01_create_user_status_table.py</code>)로 바꿔준다.
이제, student_status 테이블에 의존하고 있는 student 테이블을 만들어보자.
다시 한 번 </p>
<pre><code class="language-bash">yoyo new . -m &quot;Create user table&quot;</code></pre>
<p><img src="https://images.velog.io/images/brighten_the_way/post/f8e65faf-ed4c-4688-92aa-3a2a7e52af1b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.25.28.png" alt="">
<code>__depends__</code>에 자동으로 직전 파일이 입력되었다. 지금 만들고 있는 테이블은 사용자 정보를 저장할 것이다. 사용자를 저장할 때는 이 사용자가 &#39;가입 진행 중&#39;인지 &#39;가입 완료&#39;인지 지정해주어야 하므로, 이 상태를 정규화한 <code>user_status</code> 테이블이 먼저 있어야만 한다. 따라서 depends에 파일을 지정한 채로 바로 사용한다. 필요 없으면 지우면 된다. 나는 필요하니까 쓴다.</p>
<p><img src="https://images.velog.io/images/brighten_the_way/post/08b1baf9-afc5-4a30-bb67-d4f609856977/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.05.41.png" alt=""></p>
<p>후... 힘들었다 MySQL 정.복.
지금 코드 간격 다 맞출까 말까 고민중인데... 일단 흐린 눈으로 둬본다 🧐</p>
<h4 id="3-mysql을-대상으로-yoyo-migration-실행">3. MySQL을 대상으로 yoyo migration 실행</h4>
<p>mysql에 db 만들어져있는지 먼저 확인하기 ! </p>
<p>마이그레이션 하는 방법엔 크게 두가지가 있는데, 커맨드라인에서 바로 실행시키는 방법</p>
<pre><code class="language-bash">yoyo apply --database mysql://scott:tiger@localhost/db .</code></pre>
<p>근데 이렇게 할 일 아마 없을 것이다. 아까 만든 yoyo.ini에
<code>database</code> 라는 변수에 <code>mysql://scott:tiger@localhost/db</code> 를 지정해두고</p>
<pre><code>yoyo apply</code></pre><p>하면 테이블이 순서대로 쭈루룩 생긴다.
마이그레이션 전 후 를 비교해보면,</p>
<pre><code>yoyo list</code></pre><p><img src="https://images.velog.io/images/brighten_the_way/post/49731ee9-2235-4083-b86d-e033c6907eb3/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.56.20.png" alt=""></p>
<p><img src="https://images.velog.io/images/brighten_the_way/post/ab9db076-b610-438a-b52a-4ab653190955/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.56.32.png" alt="">
status가 달라진 것을 알 수 있다. </p>
<p>이제 열심히 다른 테이블도 만들어보자 !
마이그레이션에 대한 스트레스가 <code>1MGR</code> 줄었다고 하겠다. 미래의 나야, 내가 이 블로그 써둬서 행복하지?</p>
<h2 id="configuration-파일-숨기기">Configuration 파일 숨기기</h2>
<p><code>yoyo.ini</code>파일에 심어둔 내 데이터베이스 설정을 숨기고 싶을 수 있다. 내 username도 있고, 비밀 번호도 있으니. 다른 파일(<code>yoyo-local.ini</code>)에 선언해두고, 불러와서 쓰고 싶다.</p>
<pre><code class="language-py"># yoyo-local.ini
[DEFAULT]
database = mysql://scott:tiger@localhost/db</code></pre>
<p>이렇게 선언해두고 yoyo.ini 파일에서 불러와서 쓰면 되는데, 두가지 방법이 있다.</p>
<pre><code class="language-py"># yoyo.ini 파일

%inherit = yoyo-local.ini
%include = yoyo-local.ini</code></pre>
<p><strong>inherit</strong> : inherit 파일 설정들이 현재 파일 설정보다 먼저 실행되어, 현재 파일에서 같은 변수를 설정하면 덮어씌워짐.
<strong>include</strong> : include 파일 설정들이 현재 파일 설정보다 더 나중에 실행되기에, 현재 파일에서 선언한 설정들을 모두 덮어씀.</p>
<p>데이터베이스는 따로 현재 ini 파일에서 추가적으로 설정하지 않을 것이기 때문에 어느 것을 사용해도 상관 없지만, 나는 <code>include</code>를 사용했다.</p>
<h2 id="의문">의문</h2>
<p>아니, <code>yoyo</code>는 고유 로고 없습니까..? 🪀 노렸을 법도 한데..? 🪀🪀🪀🪀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django와 Reverse relations과 Related_name]]></title>
            <link>https://velog.io/@brighten_the_way/Django%EC%99%80-Reverse-relations%EA%B3%BC-Relatedname</link>
            <guid>https://velog.io/@brighten_the_way/Django%EC%99%80-Reverse-relations%EA%B3%BC-Relatedname</guid>
            <pubDate>Sun, 14 Jun 2020 13:26:42 GMT</pubDate>
            <description><![CDATA[<h1 id="정참조와-역참조-객체-서로-호출하기">정참조와 역참조 객체 서로 호출하기</h1>
<p>데이터베이스에서 두 테이블이 참조 관계에 있는 경우를 생각해보자. 예를 들어, <code>User</code> 테이블과 사용자의 직업인 <code>Occupation</code> 테이블이 있다. 두 테이블은 N:1 관계에 있으며, <code>User</code> 객체가 <code>Occupation</code> 객체를 참조하고 있다. <code>User</code> 가 <code>Occupation</code> 을 선택하여 입사 원서를 작성한다고 가정해보자.</p>
<pre><code class="language-python">class User(models.Model):
    name    = models.CharField(max_length = 50)
    job        = models.ForeignKey(&#39;Occupation&#39;, on_delete = models.CASCADE)
    created_at    = models.DateTimeField(auto_now_add = True)

class Occupation(models.Model):
    name = models.CharField(max_length = 50)</code></pre>
<p><code>User</code> 객체는 <code>Occupation</code> 객체를 정참조 하고 있으므로, 속성 이름으로 바로 접근 할 수 있다. User1을 선택하여, 그 사람의 job을 찾아보자.</p>
<pre><code class="language-python">user1 = User.objects.get(id = 1)
user1.job.name
&gt;&gt;&gt; &#39;Developer&#39;</code></pre>
<p>그러나 <code>Occupation</code> 객체는 <code>User</code> 객체를 역참조 하고 있으므로 바로 접근이 불가능하다. <code>developer</code> 이라는 <code>Occupation</code>을 가지고 있는     유저를 모두 찾아보자.</p>
<pre><code class="language-py">job1   = Occupation.objects.get(name = &#39;developer&#39;)
people = job1.user.all() # 이게 될까?</code></pre>
<p>❌ 안 됨 ❌</p>
<pre><code class="language-py">Traceback (most recent call last):
  File &quot;&lt;console&gt;&quot;, line 1, in &lt;module&gt;
AttributeError: &#39;Occupation&#39; object has no attribute &#39;user&#39;</code></pre>
<p>그렇다고 절대로 사용하지 못하는 것은 절대 아니니 걱정하지말자. <strong>역참조 관계에 있을 때는 <code>[classname]_set</code> 이라는 속성을 사용하여 접근</strong>해야한다.</p>
<pre><code class="language-py">job1   = Occupation.objects.get(id = 1)
people = job1.user_set.all()
&gt;&gt;&gt; &lt;QuerySet[&lt;Object User Object(1)&gt;, &lt;Object User Object(2)&gt;]&gt;</code></pre>
<p>이 때, <code>user_set</code> 대신 사용할 수 있는 것이 <code>related_name</code>이다. 역참조 대상인 <code>user</code> 객체를 부를 이름.</p>
<blockquote>
<p>즉, <code>User</code> 클래스를 정의할 때, 정참조 하고 있는 <code>Occupation</code> 클래스의 인스턴스에서 어떤 명칭으로 거꾸로 호출당할 지 정해주는 이름인 것이다.</p>
</blockquote>
<h1 id="what-related-names-do">What related names do</h1>
<p>앞의 예시를 다시 보자. 아무래도 <code>Occupation</code>의 입장에서는 입사 지원자들을 <code>appliers</code>라고 부르는 것이 더 직관적이고 편할 것 같다.</p>
<pre><code class="language-python">class User(models.Model):
    name = models.CharField(max_length = 50)
    job     = models.ForeignKey( 
            &#39;Occupation&#39;,
            on_delete    = models.CASCADE,
            related_name = &#39;appliers&#39; ------------------------- [Key Point !]
        )
    created_at    = models.DateTimeField(auto_now_add = True)

class Occupation(models.Model):
    name = models.CharField(max_length = 50)</code></pre>
<p><strong>[Key Point]</strong> 를 눈여겨 보자.
<code>User</code>객체를 정의할 때, <code>job</code>이라는 속성에 <code>Occupation</code>객체가 연결되어 정참조하고 있다. <code>Occupation</code>객체의 인스턴스와 연결되어 있는 <code>User</code> 객체를 거꾸로 불러올 때, <code>appliers</code> 라는 이름으로 부르기 위해 <code>job</code> 속성에 <code>related_names = &#39;appliers&#39;</code>를 함께 지정해주었다.</p>
<pre><code class="language-py">job1   = Occupation.objects.get(id = 1)
people = job1.appliers.all()
&gt;&gt;&gt; &lt;QuerySet[&lt;Object User Object(1)&gt;, &lt;Object User Object(2)&gt;]&gt;</code></pre>
<p>잘 동작하는 것을 알 수 있다. 모든 Foreign Key에 related_name을 붙여줄 필요는 없다. 때에 따라, 참조하고 있는 객체 이름에 <code>_set</code>을 붙이는 것이 더 직관적인 경우가 굉장히 많기 때문이다. </p>
<h1 id="related-name이-필수인-경우가-있다">Related name이 필수인 경우가 있다.</h1>
<p>바로 한 클래스에서 서로 다른 두 컬럼(속성)이 같은 테이블(클래스)를 참조하는 경우이다.
앞서 설명한 상황에서, 지원자가 필수로 신청한 <code>occupation</code>외에, 2지망인 <code>occupation</code>도 받는다고 가정해보자.</p>
<pre><code class="language-python">class User(models.Model):
    name       = models.CharField(max_length = 50)
    job           = models.ForeignKey(&#39;Occupation&#39;, on_delete = models.CASCADE)
[*] choice_2nd = models.ForeignKey(&#39;Occupation&#39;, on_delete = models.CASCADE, null = True)
    created_at = models.DateTimeField(auto_now_add = True)

class Occupation(models.Model):
    name = models.CharField(max_length = 50)</code></pre>
<blockquote>
<ul>
<li>참고로 위와 같은 선언은 애초에 마이그레이션이 되지 않는다. related_name 지정하라는 문구만 뜸.</li>
</ul>
</blockquote>
<p><code>User</code>객체에서 <code>Occupation</code>객체를 정참조 하는 속성이 두 개이다. 다시 말해 <code>developer</code>이라는 <code>Occupations</code>객체의 인스턴스를 1지망으로 선택한 지원자와 2지망으로 선택한 지원자가 따로 구별되어있다는 뜻이 된다. 아래 두 인스턴스를 보자.</p>
<pre><code class="language-py">user1 = User.objects.create(name = &#39;Nick&#39;, job_id = 1) #developer
user2 = User.objects.create(name = &#39;Sue&#39;, job_id = 2, choice_2nd_id = 1)</code></pre>
<p><code>user1</code>은 1지망은 <code>job</code>으로 <code>id</code>가 <code>1</code>번인 <code>developer</code>이다.
<code>user2</code>의 1지망은 <code>2</code>번 <code>job</code>이고, <strong>2지망</strong>이 <code>developer</code>이다.</p>
<h3 id="이-때-related_name이-없다면">이 때 related_name이 없다면?</h3>
<pre><code>job1 = Occupation.objects.get(id = 1)
job1.user_set.all()</code></pre><p>의 결과가 생성될 수 있을까?
❌ 안 됨 ❌</p>
<blockquote>
<p><code>Occupation</code>객체를 정참조 하고 있는 컬럼이 <code>job</code>과<code>choice_2nd</code>두 개이므로, 그저 user_set이라는 속성만으로는 자신을 바라보고 있는 두 User 객체 가운데 어떤 속성에 접근해야할 지 알 수가 없기 때문이다. 즉, <code>developer</code>을 1지망으로 고른 사람들의 목록(<code>Nick</code>)을 가져와야할 지, 2지망으로 고른 사람들의 목록(<code>Sue</code>)을 가져와야할 지 알 수가 없기 때문이다.</p>
</blockquote>
<h3 id="바로-이럴-때-related_name이-필수인-것이다">바로 이럴 때 related_name이 필수인 것이다.</h3>
<pre><code class="language-python">class User(models.Model):
    name = models.CharField(max_length = 50)
    job     = models.ForeignKey( 
            &#39;Occupation&#39;,
            on_delete    = models.CASCADE,
            related_name = &#39;appliers&#39; ------------------------- [Key Point !]
        )
    choice_2nd  = models.ForeignKey(
            &#39;Occupation&#39;,
            on_delete    = models.CASCADE,
            null         = True
            related_name = &#39;second_appliers&#39;
        )
    created_at    = models.DateTimeField(auto_now_add = True)</code></pre>
<p><strong>이제는 <code>developer</code>을 1지망으로 지원한 Nick과 2지망으로 지원한 Sue를 구분하여 호출할 수 있다.</strong></p>
<pre><code class="language-py">job1 = Occupation.objects.get(id = 1)

job1.appliers.all()
&gt;&gt;&gt; &lt;QuerySet[&lt;Object User Object(1)&gt;]&gt; # ---&gt; Nick

job1.second_appliers.all()
&gt;&gt;&gt; &lt;QuerySet[&lt;Object User Object(2)&gt;]&gt; # ---&gt; Sue</code></pre>
<blockquote>
<h4 id="예시에서는-foreign-key만을-다루었는데-manytomany-관계에-있을-때에도-related_name은-같은-원리로-동작한다-헷갈리지-않게-주의하자">예시에서는 Foreign Key만을 다루었는데, ManyToMany 관계에 있을 때에도 related_name은 같은 원리로 동작한다. 헷갈리지 않게 주의하자.</h4>
</blockquote>
<h1 id="마치며">마치며</h1>
<p>웹의 구조나 서비스가 복잡해질 수록, 클래스 사이의 참조가 많아진다. 일대다는 물론이고, 다대다 관계도 계속 늘어난다. 그럴 때일 수록 related name이 중요하다고 생각한다. 어떻게든 migration만 되면 되지. 라는 생각으로 related_name을 마음대로 설정하다 보면, 나중엔 변수 이름을 아무렇게나 정했을 때만큼이나 의미를 알수 없는 코드를 양산하게 되기 때문이다.</p>
<p>오늘도 많이 배웠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[위코드 1차 프로젝트 멘토링 회고록]]></title>
            <link>https://velog.io/@brighten_the_way/%EC%9C%84%EC%BD%94%EB%93%9C-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A9%98%ED%86%A0%EB%A7%81-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@brighten_the_way/%EC%9C%84%EC%BD%94%EB%93%9C-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A9%98%ED%86%A0%EB%A7%81-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Sun, 07 Jun 2020 14:56:00 GMT</pubDate>
            <description><![CDATA[<p>위코드에서 멘토로 보낸 시간의 시작을 함께한 8기 수강생분들의 1차 프로젝트가 끝났다. 매 순간이 꽃 같지는 않았지만 또 한 번 아름답게 기억될 그 과정을 잊지 않기 위해 기록한다. 원래 꽃이 지고나서야 봄인걸 알지 않나.</p>
<p><img src="https://images.velog.io/images/brighten_the_way/post/318902e7-cd98-4b57-9c65-e0188ac34b7e/IMG_6143.jpeg" alt=""></p>
<h1 id="1차-프로젝트-목표--타겟">1차 프로젝트 목표 &amp; 타겟</h1>
<p>1차 프로젝트를 진행하면서 백엔드 개발자로서 이뤄야 할 목표가 여러가지 있지만, 그 중 단연 중요한 것은 크게 세가지이다.</p>
<p><strong>1. 데이터 테이블 관계 익숙해지기</strong>
<strong>2. django와 친해지기</strong>
<strong>3. 프론트엔드 개발자와 협업하는 방법 배우기</strong></p>
<p>그러니까 이 프로젝트의 궁극적인 목적은 이론과 모델링으로만 어렴풋이 느낌을 잡았던 테이블 사이의 관계 (1:1, 1:N, N:N)를 보다 정확하게 이해하고, 서로 연결 지어진 객체들의 속성을 자유자재로 다루며 django ORM을 최대한 잘 활용하여 프론트엔드 개발자들과 함께 웹이 동작하도록 만드는 것이라는 뜻이다. 나는 과연 멘티들에게 이 목적을 잘 알려주었을까. 그랬다면 프로젝트 선정 목적과 결과를 보다 잘 이해시켜 줄 수 있었을까. </p>
<p>이 과정을 위해 선정한 서비스는 오설록, 비츠, 리모와, 라카, 정육각, 서브웨이 6개의 웹이었다. 가장 모델링이 어려울 것이라 예상했던 웹은 오설록과 서브웨이. 비츠, 라카, 정육각은 1차 프로젝트에 가장 적당한 난이도라 생각했고, 리모와는 같은 제품을 여러 카테고리에 포함시켜 놓은 것이 마치 zara 페이지와 비슷해 필터링에서 다소 헤맬 것이라 생각했다 (사실 고비는 다른데서 왔지만.. 인간적으로 웹을 실시간으로 업뎃하지는 말기로 하자).</p>
<h1 id="진행-과정">진행 과정</h1>
<p>첫 주는 모델링, 크롤링, 회원가입&amp;로그인 구현으로 보내는 것이 보통이다. 그러나 이번 8기부터 프로젝트 직전에 프론트/백 인스타그램 회원가입-로그인 연동 과정을 미리 진행해서인지 회원가입&amp;로그인에 시간을 많이 투자하는 팀은 적었다. 모든 웹이 selenium을 쓰지 않고는 크롤링이 되지 않았기 때문에 크롤링과 모델링에 거의 일주일을 투자했다.</p>
<h3 id="모델링-리뷰">모델링 리뷰</h3>
<p>1차 프로젝트 모델링은 모든 팀이 한 공간에 모여 각자의 Aquery Tool을 켜놓고 리뷰를 진행한다. 왜  다른팀 모델을 다 봐야하느냐에 대한 질문과... 약간의 원성이 들려왔다. 이 과정을 다같이 진행하는 가장 큰 이유는 각자 다른 웹을 분석했고, 그 웹을 구조화하는 방식이 다를 수 있으므로, 다른 팀의 진행 과정을 보는 것으로 또다른 공부를 할 수 있기 때문이다. 하지만 구조를 모른 채로 다른 팀의 작업까지 속속들이 집중하기란 쉽지 않다. 받은 피드백을 적어보자면 모델링 시작 전 팀원이 &#39;우리 프로젝트의 구조는 이러이러하고, 저러저러한 이유로 이렇게 모델링을 했습니다&#39; 라고 설명을 하는 것이다. 보다 유익한 시간으로 만들기 위해서.</p>
<p>이 방법도 서로의 집중력을 끌어올리기엔 무리가 있는데, 좀 더 발전시켜야겠다.</p>
<h3 id="장바구니-모델링-오해">장바구니 모델링 오해</h3>
<p>장바구니와 주문, 결제 시스템을 모델링 해 본 것이 사실 이번 프로젝트에서 처음 겪었다. 어렴풋이 알고 있던 바를 다른 멘토님들과 공유를 안해서 나는 비효율적인 방법으로 코칭을 했고, </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 2020-06-03 Wed.]]></title>
            <link>https://velog.io/@brighten_the_way/TIL-2020-06-03-Wed</link>
            <guid>https://velog.io/@brighten_the_way/TIL-2020-06-03-Wed</guid>
            <pubDate>Sat, 06 Jun 2020 09:16:32 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-진짜-역대급">오늘 진짜 역대급</h1>
<p>정신없었다.</p>
<h2 id="오전">오전</h2>
<h3 id="1000---1100">10:00 - 11:00</h3>
<p>멘토 커피 타임. 서로 너무 정신없이 일하다가 오늘 다른 분들이랑 얘기도 좀 하고, 뭐가 어려운지 얘기하고, 도움도 얻고, 힘들어 하던 부분 공유도 하고. 진짜 정신적으로 힐링되는 것과 더불어 실질적인 도움도 받아서 너무 좋았다. 2주에 한 번 이런 시간이라니 엄청 기다려질 것 같다. 오늘 너무 빠르게 떠든 것 같은데, 다음에는 좀 더 귀기울여 듣는 시간이 되길.</p>
<h3 id="1100---1145">11:00 - 11:45</h3>
<p>8기 정육각팀 멘토링. Order - Cart - CartItem - Product 테이블이 각자 있는 팀인데, <code>order table</code>만 주문 상태를 관리하는 status column이 있고, cart table엔 status 관리용 column이 없었다. 덕분에 상태 관리가 안되어서 현재 활성화된 cart 객체를 가져올 때 <code>Cart.objects.filter(user_id = user_id).all().last()</code> 로 고객의 카트 가운데 가장 마지막에 생성된 객체에 접근했다. 이런 방법을 사용하면 다음과 같은 문제가 발생한다.</p>
<ol>
<li>의미 없이 한 고객의 모든 주문 정보를 불러와야 한다.</li>
<li>정확히 지칭한 cart    객체가 아닌 대상을 (모호하게) 불러온다.</li>
<li>해당 cart가 이미 주문이 끝난 객체인지, 카트에 물건이 계속 담기는 중인지, 아니면 아예 주문이 취소된 객체인지 관리할 길이 없다.</li>
</ol>
<p>가장 쉽게 문제를 해결하는 방법은 우선 정도를 따르는 것이다.
cart 테이블에 status 관리용 coulmn을 추가하고, status 자료만을 모아놓은 status 테이블과 one-to-many관계를 지어준다. 이제 우리는 원하는 카트를 정확하게 지칭할 수 있다.</p>
<pre><code>Cart.objects.get(user_id = user_id, status_id = 1)</code></pre><p>더이상 불특정 다수의 카트 객체를 모두 불러올 일이 없고, 활성화된 상태인 단 하나의 카트를 불러올 수 있게 되었다.</p>
<h2 id="점심">점심</h2>
<p>용케 아침에 싸온 불고기랑 오렌지 도시락 먹음. 
ㄱㄱㅎ님이랑 ㄱㅌㅅ님이랑 도란도란 나눠먹음.</p>
<h2 id="오후">오후</h2>
<p>오후 내내 거실에서 멘토링. 후...
일단 내 목표는 팀에서 천천히 가는 팀원 한 명이 무조건 API 하나라도 제대로 만드는 것.
Get하나 Post하나
... 욕심일까 ?</p>
<pre><code>마법의 소라고둥님 제가 욕심을 부리고 있는걸까요 ? &lt;네니요&gt;</code></pre><h3 id="django-몰랐던-사실">django 몰랐던 사실</h3>
<ul>
<li><h3 id="오늘의-걱정거리">오늘의 걱정거리</h3>
</li>
<li><p>main url 과 app url을 아직 분리 못하면 어떻게 해야하지 (1차 프로젝트 2주차 수요일인데)</p>
</li>
<li><p>상세 데이터 꺼내서 JSON 만들어 줄 때, products = Product.objects.all() 하고 for loop 돌려서 각 객체 꺼내와야 한다는 걸. 바로 알려주는 것이 맞나? -&gt; 맞음!</p>
</li>
<li><p>offset 이랑 limit은 무조건 걸어주는 걸로 ! 조건이 없어도 우선 무조건.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[8기 위모아팀 전설의 크롤링]]></title>
            <link>https://velog.io/@brighten_the_way/8%EA%B8%B0-%EC%9C%84%EB%AA%A8%EC%95%84%ED%8C%80-%EC%A0%84%EC%84%A4%EC%9D%98-%ED%81%AC%EB%A1%A4%EB%A7%81</link>
            <guid>https://velog.io/@brighten_the_way/8%EA%B8%B0-%EC%9C%84%EB%AA%A8%EC%95%84%ED%8C%80-%EC%A0%84%EC%84%A4%EC%9D%98-%ED%81%AC%EB%A1%A4%EB%A7%81</guid>
            <pubDate>Wed, 03 Jun 2020 14:20:13 GMT</pubDate>
            <description><![CDATA[<p>커스터마이징 캐리어를 소개하는 웹이다. 
꽤나 단순한 줄로만 알았다. 
근데 한 페이지 로딩하는데 슬립을 10초씩 줘야하더니
크롤링 하는 동안 실시간으로 웹이 업데이트 되는게 아닌가.
오늘 아침에 긁었다가 점심에 긁으면 드롭다운 옵션이 생겨있고, 저녁에 다시 긁으면 웹 구조가 완전히 달라져있는 마법. 
그렇게 모델이 다 짜지고, 기능까지 다 구현되는 내내 크롤링을 했다고 한다. 
전격 위코드 최초 프로젝트 내내 크롤링과 함께한 팀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS EC2 인스턴스 접속할 때 사용하는 키-쌍 파일 (.pem)을 잃어버렸다면?]]></title>
            <link>https://velog.io/@brighten_the_way/AWS-EC2-key-pair-loss</link>
            <guid>https://velog.io/@brighten_the_way/AWS-EC2-key-pair-loss</guid>
            <pubDate>Sun, 17 May 2020 12:27:04 GMT</pubDate>
            <description><![CDATA[<h1 id="문제-발생---ec2-key-분실">문제 발생 - EC2 key 분실</h1>
<p>새로운 맥북을 구입한 기쁨을 만끽할 새도 없이, 생각보다 백업을 너무 안했다는 것을 점점 깨닫는 요즘이다. 한동안 aws 서버에 접속할 일이 없어 잊고 지냈는데, EC2 인스턴스에 접속할 때 사용하는 키페어인 <strong>someone_key_aws.pem</strong> 파일이 사라진 것이다. 행복하지 않다. 위코드 1차 프로젝트 베라 서버 열어달라는 요청을 받고 알게 된 너무나 큰 사실.. 이런 일이 자주 생길 것 같아 이 기회에 정리해본다.</p>
<blockquote>
<p>❓<strong>키 페어</strong>
Amazon EC2는 퍼블릭 키 암호화 기법을 사용하여 로그인 정보를 암호화 및 복호화합니다. 퍼블릭 키 암호화 기법은 <strong>퍼블릭 키를 사용하여 데이터를 암호화하고, 수신자가 프라이빗 키를 사용하여 해당 데이터를 복호화하는 방식</strong>입니다. 퍼블릭 키와 프라이빗 키를 키 페어라고 합니다. 퍼블릭 키 암호화 기법을 사용하면 암호 대신 프라이빗 키를 사용하여 인스턴스에 안전하게 액세스할 수 있습니다. [<a href="https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/ec2-key-pairs.html">aws-key pair</a>]</p>
</blockquote>
<h1 id="해결-방법">해결 방법</h1>
<blockquote>
<p>암호화된 채 저 멀리 사라진 키를 되찾아오는 방법은 없다. 새로운 인스턴스와 키 페어를 생성한 뒤, 원본 인스턴스의 스냅샷을 복제하여 백업하고, 새로운 키 페어를 원본 인스턴스에 붙여야한다.</p>
</blockquote>
<hr>
<h2 id="기존-인스턴스-이미지-백업">기존 인스턴스 이미지 백업</h2>
<p>키 페어를 잃어버린 내 원본 인스턴스를 선택하여 [작업] - [이미지] - [이미지 생성]을 선택하여 백업 이미지를 만든다. </p>
<blockquote>
<p>❓<strong>이미지, AMIs (Amazone Machine Images)</strong>
EC2 인스턴스를 그대로 저장해서 재사용할 수 있도록 만든 것입니다. 현재 서버의 하드웨어, 소프트웨어 설정, 어플리케이션등을 그대로 사용할 수 있습니다. Private(비공개 개인 이미지), public(누구나 사용할 수 있는 공개 이미지), Marketplace(판매, 구매 가능한 이미지) 세 종류가 있습니다.
(참조 : <a href="https://ithub.tistory.com/56">https://ithub.tistory.com/56</a>)</p>
</blockquote>
<hr>
<h2 id="기존-인스턴스-정지stop--새로운-인스턴스-생성">기존 인스턴스 정지(stop) &amp; 새로운 인스턴스 생성</h2>
<p><a href="https://velog.io/@k904808/AWS-1">AWS EC2 인스턴스를 생성하는 방법</a>은 위코드 동기 kay님 블로그를 참조했다. 새로운 인스턴스를 생성하고, 기존의 인스턴스는 중지시킨다.
<img src="https://images.velog.io/images/brighten_the_way/post/48072858-effc-449b-a7cf-daa39bdaccb8/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-05-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.01.04.png" alt=""></p>
<hr>
<h2 id="인스턴스-볼륨-detach--attach">인스턴스 볼륨 detach &amp; attach</h2>
<ol>
<li>AWS 왼쪽 배너 중 ELASTIC BLOCK STORE - Volumes에서 <strong>키 페어를 분실한 EC2 인스턴스</strong>의 볼륨을 분리(detach)한다.</li>
<li><strong>키 페어를 분실한 EC2 인스턴스의 볼륨</strong> 을 다시 선택해서 <strong>새로운 EC2 인스턴스</strong> 에 붙인다(attach).
<img src="https://images.velog.io/images/brighten_the_way/post/4da38fde-8cea-4899-8f5d-5b09c185a116/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-05-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.48.11.png" alt=""><blockquote>
<p>❓<strong>Amazon EBS (Elastic Block Store) 와 볼륨</strong>
인스턴스 스토어와 EBS 모두 아마존 EC2 인스턴스와 관련있는 저장용 스토리지입니다. 데이터를 저장하는 것은 물론이고, 스냅샷 기능을 제공해서 EBS의 현재 상태를 그대로 보존할 수 있습니다. 인스턴스 스토어는 이름에서 알 수 있듯 임시로 저장하는 공간이기에, 데이터를 장기적으로 유지하거나 암호화하려는 경우에는 EBS 볼륨을 사용하는 것이 이상적입니다. EBS 볼륨은 EBS로 생성한 스토리지 디바이스입니다.</p>
</blockquote>
</li>
</ol>
<hr>
<h2 id="인스턴스-접속-후-볼륨-마운트">인스턴스 접속 후 볼륨 마운트</h2>
<ol>
<li><p>생성된 새로운 키페어를 이용하여 <strong>새로운 EC2 인스턴스</strong>에 접속한다.</p>
<pre><code>ssh -i /Users/shlee/Downloads/key_soheon_backend.pem ubuntu@ec2-54-180-157-216.ap-northeast-2.compute.amazonaws.com&quot;</code></pre><blockquote>
<p>.zshrc or .bashrc에 인스턴스 접속 명령어를 alias로 지정해두면 매번 aws 주소를 입력하지 않아도 되어서 편하다.</p>
</blockquote>
<pre><code>alias aws=&quot;ssh -i /Users/shlee/Downloads/key_soheon_backend.pem ubuntu@ec2-5    4-180-157-216.ap-northeast-2.compute.amazonaws.com&quot;</code></pre><p>처음 접속했을 때는 아무것도 없는 빈 우분투를 맞이하게된다. 좌절하지 말자.</p>
</li>
<li><p>볼륨을 마운트한다.</p>
<pre><code>sudo mount /dev/sdf1 /mnt
or
sudo mount /dev/sdf /mnt</code></pre><h1 id="우선-성공">우선 성공</h1>
<h2 id="결과">결과</h2>
<p>다시 다 돌아왔다. 다시 나는 행복해졌다.
<img src="https://images.velog.io/images/brighten_the_way/post/46bf9be5-6c7f-48d1-b504-922efb33719d/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-05-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.49.23.png" alt=""></p>
</li>
</ol>
<h2 id="그런데">그런데</h2>
<p>이것은 새로운 인스턴스를 생성한 것이다. 새로운 인스턴스와 새로운 키 페어를 만들고, 그 새로운 인스턴스에 모든 것을 옮겨온 것이다. 기존 인스턴스에 새로운 키 페어를 결합한 것이 아니라는 뜻이다. 새로운 인스턴스를 사용해도 되지만, 기존 인스턴스를 유지하고자 하는 경우는 아래와 같은 작업이 추가로 필요하다.</p>
<ol>
<li>/mnt/home/ec2-user/.ssh/authorized_keys 파일을 수정하여 새 공개 키로 교체</li>
<li>sudo umount /mnt를 입력하여 볼륨 마운트 해제, ELASTIC BLOCK STORE → Volumes로 이동한 뒤 임시 EC2 인스턴스에서 키 쌍을 분실한 EC2 인스턴스의 볼륨을 Detach</li>
<li>키 쌍을 분실한 EC2 인스턴스의 볼륨을 원래 EC2 인스턴스에 Attach(Device는 /dev/xvda로 설정)</li>
<li>EC2 인스턴스를 시작(start), 교체한 키 쌍을 사용하여 SSH로 접속</li>
</ol>
<p>나는 이 과정을 아직 진행하지 못했다. 이유는 authorized_keys 파일을 열었을 때 암호화되어 있는 키를 보았다. 무언가 굉장히 긴. 막연한 두려움에 파일을 닫았다. 긴 코드 울렁울렁.. 이걸 어떻게 새 공개 키로 교체하는지 아직 모르겠다. 다시 또 싸워야 한다. 영원한 고통 server...</p>
<h1 id="참고">참고</h1>
<p>키 쌍 파일(pem)을 분실했다면?
<a href="http://pyrasis.com/book/TheArtOfAmazonWebServices/Chapter07/01">http://pyrasis.com/book/TheArtOfAmazonWebServices/Chapter07/01</a></p>
<p>EC2 서버 생성하기
<a href="https://velog.io/@k904808/AWS-1">https://velog.io/@k904808/AWS-1</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[REST API vs. GraphQL]]></title>
            <link>https://velog.io/@brighten_the_way/REST-API-vs.-GraphQL</link>
            <guid>https://velog.io/@brighten_the_way/REST-API-vs.-GraphQL</guid>
            <pubDate>Sun, 10 May 2020 14:58:29 GMT</pubDate>
            <description><![CDATA[<h1 id="restful-api">RESTful API</h1>
<p>개발을 배운 이래로, 보다 REST에 가까운 url을 작성하고자 많은 시간을 들였다. 내 첫 url은 &#39;localhost:5000<del>/product/main-page</del>&#39; 이었는데, 누가봐도 &#39;아..저게 무슨..&#39; 이라고 생각할 만하다.
REST API는 현재도 가장 보편화된 웹 API 디자인이지만, 원하는 정보가 시시각각으로 바뀌는 요즘 같은 환경에서는 적절하지 못하다는 의견이 꽤 많다. 적절하지 못하다? 그게 뭘까?</p>
<h3 id="오버-페치--언더-페치">오버 페치 &amp; 언더 페치</h3>
<p>사용자의 이름과 나이만 필요한데, 전화번호나 주소까지 다 전달 될 때. 혹은 기껏 필요한 자료만 전달하도록 해놓았더니 다시 &#39;아 미안한데, 핸드폰 번호는 줘&#39; 라고 할 때.. TMI와 TLI를 오가는 경우가 왕왕 발생한다. 오버 페치다.</p>
<p>제품의 세부 정보와, 그 제품을 구입한 사람들의 후기가 필요한 경우, 제품과 후기를 각각 따로 요청해야 한다. 서로 다른 엔드포인트에 (거의) 동시에 접근해야하기 때문이다. 즉, 필요한 정보를 한 번에 충분히 제공하지 못한다는 것을 의미한다. 언더 페치다.</p>
<p>또, 다루는 자료의 depth가 깊어지거나, 복잡해질 경우, url이 계속 길어지는 단점이 생긴다. 이대로 가다간 언젠가는 query string이 지구 끝까지 이어질 것만 같다.</p>
<blockquote>
<p>/product/3
/product/3/nutrition
/product/3/allergy
/product/3/allergy?category=3</p>
</blockquote>
<h1 id="graphql">GraphQL</h1>
<p>일반적으로 여러 엔드 포인트에 접근하여 데이터를 가져와야 하는 REST API와 달리 GraphQL에서는 <strong>구체적인 데이터 요구 사항이 포함된 단일 쿼리</strong>를 GraphQL 서버에 보내기만 하면 된다.
베스킨 라빈스 아이스크림 상품의 이름과 속한 카테고리를 얻고자 한다면, 아래와 같은 request를 프론트엔드로부터 받는다.</p>
<pre><code>query {
    Product(id:3) {
        name_kr
        name_en
        category {
            name
        }
    }
}</code></pre><p>음, 3번 제품의 정보!
그럼 아래와 같이 전달해주면 된다.</p>
<pre><code>{
    &quot;data&quot;: {
        &quot;Product&quot;: {
            &quot;name_kr&quot;: &quot;초코나무 숲&quot;,
            &quot;name_en&quot;: &quot;CHOCOLATE FOREST&quot;,
            &quot;category&quot;:{
                &quot;name&quot;: &quot;아이스크림&quot;
            }
        }
    }
}</code></pre><p>클라이언트가 GraphQL을 사용하여 쿼리 내부에 필요한 데이터를 정확하게 지정할 수 있다.</p>
<h2 id="프론트엔드-관점-장점">프론트엔드 관점 장점</h2>
<p>REST API의 일반적인 패턴은 앱 내부에있는 뷰에 따라 엔드 포인트를 구성하는 것이다. 프론트엔드가 해당 엔드 포인트에 접근하기만 하면 필요한 모든 정보를 얻을 수 있으므로 편리하다.</p>
<p>하지만 UI가 변경 될 때마다 필요한 자료는 바뀌므로, 새로운 요청을 고려하여 백엔드를 조정해야한다. </p>
<p>GraphQL을 사용하면 이 문제가 해결된다. 서버에서 추가 작업을하지 않고도 클라이언트 측을 변경할 수 있기 때문이다. 프론트 엔드에서 정확한 데이터 요구 사항을 지정할 수 있으므로 백엔드 엔지니어가 조정할 필요가 없다.</p>
<p>또한, 프론트엔드에서부터 데이터 구조에 직접적으로 접근하다고 볼 수 있으므로, 요청을 보내는 클라이언트 쪽에서도 사용 가능한 데이터가 어떻게 구성되어 있는지 보다 깊이 이해하고 있어야 한다.</p>
<h2 id="그게-어떻게-가능한가-둘-다-바쁜데">그게 어떻게 가능한가, 둘 다 바쁜데</h2>
<h3 id="스키마-schema">스키마 (Schema)</h3>
<p>스키마는 클라이언트와 서버 간의 계약으로 클라이언트가 데이터에 액세스하는 방법을 정히하는 것이다. API에 노출되는 모든 유형은 GraphQL 스키아 정의 언어를 사용하여 스키마에 기록된다. 스키마가 정의되면 해당 팀이 네트워크를 통해 전송되는 데이터의 명확한 구조를 알게되기 때문에 추가 커뮤니케이션 없이도 원활히 작업을 수행할 수 있다 (이론적으로 ㅎ).</p>
<p>스키마에 대해서는 또 추가적으로 알아보도록 하자.
결론. 이제 수많은 엔드포인트 주소를 프론트엔드에게 알려주지 않아도 된다. 프론트님~ 쿼리 잘 짜서 데이터 가져가시면 돼요! 라고 해보자..</p>
]]></description>
        </item>
    </channel>
</rss>