<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[나의 얼렁뚱땅]]></title><description><![CDATA[a blog on software engineering]]></description><link>https://jihoon-ernesto.github.io</link><generator>GatsbyJS</generator><lastBuildDate>Mon, 17 Jul 2023 13:25:12 GMT</lastBuildDate><item><title><![CDATA[나의 얼렁뚱땅 오픈소스 참여기 - part 3]]></title><description><![CDATA[(이전 글: 나의 얼렁뚱땅 오픈소스 참여기 - part 2) “어, 이거 왜 안 돼? 내 코드 어디 갔어!” 여느 때와 마찬가지로 VS Code…]]></description><link>https://jihoon-ernesto.github.io/my-first-open-source-part3/</link><guid isPermaLink="false">https://jihoon-ernesto.github.io/my-first-open-source-part3/</guid><pubDate>Mon, 01 May 2023 00:25:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;(이전 글: &lt;a href=&quot;../my-first-open-source-part2/&quot;&gt;나의 얼렁뚱땅 오픈소스 참여기 - part 2&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;“어, 이거 왜 안 돼? 내 코드 어디 갔어!”&lt;/p&gt;
&lt;p&gt;여느 때와 마찬가지로 VS Code를 열고 뭔가 작업을 하던 중이었다. 누를 때마다 뿌듯해하던 나의 터미널 단축키, &lt;code class=&quot;language-text&quot;&gt;cmd+.&lt;/code&gt;이 동작을 안 하고 있었다. 뭔가 안 좋은 느낌이 스치고 지나갔다. 무슨 일인가가 생긴 것이다. 순간, 얼마 전에 VS Code가 업데이트되었던 것이 떠올랐다. 그래, 뭔가 바뀌었어.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;그러고 나서도 한참 시간이 흘렀다. 약간의 짬이 생긴 주말 저녁이었다. 성질 나는데 그 문제나 한번 알아볼까? 물론 진짜 성질이 난 건 아니었다. 다만, 나의 유일무이한(!) 오픈소스 업적이 훼손된 것에 대한 찜찜함이 마음 한켠에 남아있던 참이었다.&lt;/p&gt;
&lt;p&gt;일단, 어느 시점에 내 코드가 사라진 것인지 조사했다. 사라진 코드를 찾는 커맨드는 &lt;code class=&quot;language-text&quot;&gt;git log -G&lt;/code&gt; 라고 검색이 되었다. VS Code의 최신 코드를 pull 받은 후, 그걸로 내 코드의 주석 부분을 검색했다. 코드 자체는 이후의 리팩토링 등으로 변경되었을 수도 있으므로 주석을 찾는 게 더 나을 거라는 생각이 들었다. 내 코드의 주석은 &lt;code class=&quot;language-text&quot;&gt;// Break: ctrl+C&lt;/code&gt; 이었으므로&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; log -G&lt;span class=&quot;token string&quot;&gt;&quot;//\sBreak:\sctrl\+C&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--oneline&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;으로 찾아보았다. 나왔다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;de450f991c2 &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; basic contextual commands &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;#160952)&lt;/span&gt;
58af29738a1 Add terminal keybinding &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; cmd+. → ctrl+c to match macOS Terminal
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;END&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;58af29738a1&lt;/code&gt;가 내가 작성한 커밋이었으니, 그 위에 표시된 &lt;code class=&quot;language-text&quot;&gt;de450f991c2&lt;/code&gt;가 문제의 커밋, 내 코드를 무자비하게 없애버린 커밋일 터였다. GitHub의 VS Code 저장소에서 검색을 하니 그 커밋에 대한 아래 페이지로 연결이 되었다.&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/54bef095d0ce32eab7b6f7d85f65aa21/bfd4b/vscode-commit-deleting-my-code.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 55.69620253164557%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB3UlEQVR42nWS264UIRBF+/8/Rb/IqJnjOU7fZrjfoellGkcTHyRZKWoXkNrAJGxkkZGfz8hDR3xMhJjwMeNC+suV/9YyUjseQqFtQCiDcQGpLS5mpuA8Skik0mhjeUrNJizWR6wPGOexLuB8xIU48pDy0FKu1NbJ9SDVg1wak1aG29s7y/5k25+su+AufncVUvkHH//M8yvPQ7vifrlLlUkIxf2+YKzDhzgIKVLaQW0Hpbb/kkvF+TAY+2JiyrmgtEEpiTFXVFhrMVpRSoHz5Oydsx/0EV+cnWucr7p3Hu8909Fhln4IrR20WthU5PvmWKVnEZa7sMwDw/w0LNLxsAmdGiYfAxEK9rJ82bLes2376Kwmi/CZu8n41nlXidsj8P7QfDw1OlV8PXC14+ox1rjBSTpOptYZludlHQcHo1jzxnv9QBTJdyn4us/c9hs/5Mwa1OCqiaLRh0VWg2gG3wPT58+fWNf1b4fO6WFt843QOr6do6NwdGI/X0A+If2hM7TST6Z5nscf3PYdpTU5ORaZ+LI53qRmt4nNBFYT2XQYzNKNe12UZ3cZmQ5EbNjcmK6XUi6OTx1jpNTE7ho3WVgeio9NvtB8WyRvu+EuHbuNiFBR6UDnjsodXzq/AOfMTWFISxktAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;the commit deleting my code&quot; title=&quot;&quot; src=&quot;/static/54bef095d0ce32eab7b6f7d85f65aa21/f058b/vscode-commit-deleting-my-code.png&quot; srcset=&quot;/static/54bef095d0ce32eab7b6f7d85f65aa21/c26ae/vscode-commit-deleting-my-code.png 158w,
/static/54bef095d0ce32eab7b6f7d85f65aa21/6bdcf/vscode-commit-deleting-my-code.png 315w,
/static/54bef095d0ce32eab7b6f7d85f65aa21/f058b/vscode-commit-deleting-my-code.png 630w,
/static/54bef095d0ce32eab7b6f7d85f65aa21/40601/vscode-commit-deleting-my-code.png 945w,
/static/54bef095d0ce32eab7b6f7d85f65aa21/78612/vscode-commit-deleting-my-code.png 1260w,
/static/54bef095d0ce32eab7b6f7d85f65aa21/bfd4b/vscode-commit-deleting-my-code.png 1871w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption class=&quot;left&quot;&gt;내 코드를 지워버린 문제의 커밋&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;그리고 이 커밋을 포함한 PR은 #160952 라고 나와 있었고,&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/3caf2988d3027981b97070a3dc8a8813/bfd4b/vscode-pr-of-the-commit.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 55.69620253164557%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAABlklEQVR42oWRyW4UMRRF6/8/ix1ZAQs2REEiQ3dXuVwuz2MdZIcOhERg6epZ1/Z59vUkteckA/fCMyuPdl0BFzLWxxcZd1VAKs2ybihtWbd9VLVbQihMIXmsN6jdoLVhnRfE+YLaFGrXbGof1bowpI3Fh4Q2jhAzuTRKaUinEUYx3X1d+PLxgVWunM9n5nlmXVdO5wuXdeMiNUIZjuMY+nscPHs395/5cHfD9HSbuf3kcN4TYiKmhE8ZGwsqVFbf2Hwdfs6Fd5hjtFaprTKJ5YxUgm1TGOvYjcU4hzaGnDLBe7wPpFwptY2mLkRyqeTy3KD3cMGhg2GSi2CTO7M0xJRJKY/aD3RAbQe1NUqtQ9c9Pct5Ea+ffxxMfdJvIFZJ6V1zHiql0I7nhP58Za5lrPUzyyKIMb7AXoAhxPERxtqRVZdzbvittXczq7WOPX39CnsNFCu2A/vHxET6Bf4n0Lo3/rvA/8GuQGV2QomEHPE5kEr+DRRCYIwdgXfwrvfhp5FpeQPMJfPt6Ts/5CMnM/Own5Be8RNqQ1erSqv+vAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;the PR of the commit&quot; title=&quot;&quot; src=&quot;/static/3caf2988d3027981b97070a3dc8a8813/f058b/vscode-pr-of-the-commit.png&quot; srcset=&quot;/static/3caf2988d3027981b97070a3dc8a8813/c26ae/vscode-pr-of-the-commit.png 158w,
/static/3caf2988d3027981b97070a3dc8a8813/6bdcf/vscode-pr-of-the-commit.png 315w,
/static/3caf2988d3027981b97070a3dc8a8813/f058b/vscode-pr-of-the-commit.png 630w,
/static/3caf2988d3027981b97070a3dc8a8813/40601/vscode-pr-of-the-commit.png 945w,
/static/3caf2988d3027981b97070a3dc8a8813/78612/vscode-pr-of-the-commit.png 1260w,
/static/3caf2988d3027981b97070a3dc8a8813/bfd4b/vscode-pr-of-the-commit.png 1871w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption class=&quot;left&quot;&gt;내 코드를 지워버린 문제의 커밋의 PR&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;이건 다시 이슈 번호 #151937 에 대한 것이라고 했다.&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/756230b9529ce55b74bf6d384fc31f95/bfd4b/vscode-issue-of-the-pr.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 55.69620253164557%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAABwUlEQVR42m2S3W7UMBCF9/3fiitUuCqVioS0tAS1uxvHjv8d20k+ZHeBUjrS5Di253jmzByUjZxkYhCBUUdcSPi4EFLu+Ndf/tu50hYhZ7T1yNl01MaTUuWQcsQHgxICYwyztkyqXXZ9rWaNakHGY6zHOE9MGesCaSmUulHrhgoW4TSHh6+Su09PzEpxPp2ZpolxFCilkFJyGQWTVFjncD7w1nb2jjfDLR+ONxwe7x3HW0daEkvOLEvuWEqllELKK2Xdf0ez7zvrtnV8zw5391+YjcJ638uwPnTsxEsmNU+ZmBZiKsSlEGLq+1obaq3/Eq7rRoyp62etQ2uNuerX0DmH954QAj6WP9nmnJHTREgRvQRSSKy5cGiHznlGMRFi7NqJ2fEsLbOL1Lp2f2t13TgOJz5/e+Dj8J3x6UKS9kroA6MQvcQYY8+2ZdC0bLhtW/fXsrVHnI/s2xsN28eHiJSqBzfCVmbLNueCtZYQYm/S60bUtTJpSSyJUCIhR3LNV0If+PH4yDTJTqyN7dn9NyJXvuln5TJEHsTAoJ45e8GTPaOCfiFsnWrCN2yj0vDdsbhu6UtFnXOvZEkLJZfuTZZfj5lTdGF+t8MAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;the issue of the PR of the commit&quot; title=&quot;&quot; src=&quot;/static/756230b9529ce55b74bf6d384fc31f95/f058b/vscode-issue-of-the-pr.png&quot; srcset=&quot;/static/756230b9529ce55b74bf6d384fc31f95/c26ae/vscode-issue-of-the-pr.png 158w,
/static/756230b9529ce55b74bf6d384fc31f95/6bdcf/vscode-issue-of-the-pr.png 315w,
/static/756230b9529ce55b74bf6d384fc31f95/f058b/vscode-issue-of-the-pr.png 630w,
/static/756230b9529ce55b74bf6d384fc31f95/40601/vscode-issue-of-the-pr.png 945w,
/static/756230b9529ce55b74bf6d384fc31f95/78612/vscode-issue-of-the-pr.png 1260w,
/static/756230b9529ce55b74bf6d384fc31f95/bfd4b/vscode-issue-of-the-pr.png 1871w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption class=&quot;left&quot;&gt;내 코드를 지워버린 문제의 커밋의 PR에 대한 issue&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;뭔가 복잡하게 돌아가는 것을 보니… 누군가가 그냥 심심해서 내 코드를 지운 건 아닌 것 같았다.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;좀 더 추적 조사한 결과, 결국 원인이 밝혀졌다. ‘Terminal Quick Fixes’ 라고 이름붙은 기능이 들어가기 위해서 내 코드가 희생된 것이었다. T_T&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/3ddcfc74febba4dbac6047f3a1adae94/4779f/vscode-release-note-1-72.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 66.45569620253164%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC0UlEQVR42o2Sy09UZxjGJ6wVWVCaqhlhtIJ25DLIiCQuXLgh0qap6cZNd110wUJmhsugoK2XhVGDEEkYLoUEuuu/wNruG+uC4ohAGOZyzpzLd75zzs9836DYhUnf5Fl8+fI+7/M+7xNJDWfJ3PmNu5P3mJj4leHhLCMjWcbGbjM6Ok42O0E2e4exAwyPZMlkxhgfn+Thw8fcn5zk1qM5flp5zc8v1okQhgS+RFUYhjiuQ9WysW0LIQTSE/jCQ7oCKQSeJ5DSw/NqkFLiS0EYBpoj4vs+plnVnxBSKJYoVkwsy8KsVrEME6ds4JQrOKUKVcOkXKlQLpcxTRPhunpwGNYERYIgoGoaerKq4v4+hcIee3s1FAoFSuUSJcOiaFiYlo3rOLiuq9VJP8ByXDSjUqgId8pVKnaN0BUCx641eWplWbPjc+V6EsNyP74jQRDqCTIIteR/Nzb4+9U/bLzJk3+3Q/7tO7Y2N9l8s0n+bZ6trS22t7fZ3d3VUGsrv6X0DxXalqUfStGPN36grSPBpavXiPf0kbh4mSuJBJ2JTnp6k1xKJonH4xotLS0sLCzoXtu2Dz00DKNG6Hl8/911WqJfkey+QHdXnPb2dhJdXbSebeV0LEY0GqW5uZlYLEZTUxPz8/O613GcQ4VKtlrd91wGvh3gRM8NLlz/hdNXbtL45SlOHqvnxMnjNH7RyNEjR6mvr6ehoYG6ujpmZmY0kdQpgYiSqS6mCFW+njyf4/bTNR68+JO7z1ZJpzMMpVMMDaVIpVKk02mNTCbD4OAg6+vryBB97f8o9A4mhIFPKIXO5P8p4XkULYEffBIb5aFOfBCwuvoHM7NzTOeWmM0ts7a4xOJCjpWVZX5fXiaXy+lDKO+mpqZ4+fIvdkwPS3xy5Q+GqsT39/cTbYtzLtnH2Xg3vee+ofd8G32dHZxvj3Pm6zP6IArKy+fT0/gHeVSE7wGOuURLWm6UmgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;the release note of VS Code 1.72&quot; title=&quot;&quot; src=&quot;/static/3ddcfc74febba4dbac6047f3a1adae94/f058b/vscode-release-note-1-72.png&quot; srcset=&quot;/static/3ddcfc74febba4dbac6047f3a1adae94/c26ae/vscode-release-note-1-72.png 158w,
/static/3ddcfc74febba4dbac6047f3a1adae94/6bdcf/vscode-release-note-1-72.png 315w,
/static/3ddcfc74febba4dbac6047f3a1adae94/f058b/vscode-release-note-1-72.png 630w,
/static/3ddcfc74febba4dbac6047f3a1adae94/40601/vscode-release-note-1-72.png 945w,
/static/3ddcfc74febba4dbac6047f3a1adae94/78612/vscode-release-note-1-72.png 1260w,
/static/3ddcfc74febba4dbac6047f3a1adae94/4779f/vscode-release-note-1-72.png 1837w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption class=&quot;left&quot;&gt;VS Code 1.72 버전의 release note&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/da5ff20270eaeecfd4f2cecae0993655/acf8f/vscode-twitter-on-terminal-quick-fixes.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 80.37974683544303%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsTAAALEwEAmpwYAAADBUlEQVR42oWU209TaRDA+7LuRhOjXOQSyqUUKQGxWAoqKiCKEhXwsvGGbrK77Prmgw+bTTYh3jXEF40vxr/AR6NGY2JUBMFLfFCgLYiaFay09HJOey5tT3+bnhZ0A9VJJjPfnHy/mcl3Zgwuv4YcY55osSjhUIh37z8giiE0LY6qRohEkqpGvvJT8Xg8jsEvSgihEOFwWAfF40nglBhhzCPinprE/XmaQCDItyQBSyQ1CEIQn8+Hx+vVgykeblFmwiMgCgJhSUaSJFRVnaskHdQQCAQICgLemRlisS+9xxSRgM+Lz+9nZsaHx+NlenpaPyfAiqLMJUj4s3cNC2VJyMfJKYZHRnG6xnC6XLp1OJy6jo2P698cTpduX78Z5pPbnQTqbab0a6AgiITDErIsE4lE0TRNryKhCX9WZ8/frXBi4h03b9/l1p17PHjYR1//IP2Dz3k69ILBZy/ofzrEo74BHj8ZYGDoOc9evkKS5PnAaDSq2wuXrvBDRgl5pTaWG6tYbqzEVFGN0WLDaKknq2g1WUXVZBSuoqDcrsdGneMLAZOln+m9yrJCK3VNHZTVNGOuaaLMuolcs52Mohoyi9eQbaplRamdrBIb2SYbIwsDkxWeunhZv9h5qJutHYfZ0tHFlvYuGlr3Um5robhqI/nla8kx28ky2cgrq8Phepse2HOmlx+XGbHWNWOtb6La3khV7Sas9c2sWdeCvWErq2obKTBbySywkJlfzqhjLD3w5OnzLFqcSWFJBes2tHDk6O8cOPgLrdvbaduxh9a2Dna27yUn30RegZkV+SUMjzjSA/853YthcQ4VNQ1YbOupsG/EumEblfZGLNb1rK7fTGnVWpbmruSnjGKWZJsZHnXNB2pa8lEe3r/Bz/v3ceTPv+j++xzHei5zrOcax89e5/AfJ+g88Bu7D3Wza/+vbOvsYvueo3z4d3I+cG70YiqCKOAPCASDor5RVEVJjVzkf5sn0VUsGk3OcjpgKCwhhiT9Z5VkRV9hsqLocVlRvwxCakMlNc5/3ggQ9iwu31cAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;Tweet on Terminal Quick Fixes&quot; title=&quot;&quot; src=&quot;/static/da5ff20270eaeecfd4f2cecae0993655/f058b/vscode-twitter-on-terminal-quick-fixes.png&quot; srcset=&quot;/static/da5ff20270eaeecfd4f2cecae0993655/c26ae/vscode-twitter-on-terminal-quick-fixes.png 158w,
/static/da5ff20270eaeecfd4f2cecae0993655/6bdcf/vscode-twitter-on-terminal-quick-fixes.png 315w,
/static/da5ff20270eaeecfd4f2cecae0993655/f058b/vscode-twitter-on-terminal-quick-fixes.png 630w,
/static/da5ff20270eaeecfd4f2cecae0993655/40601/vscode-twitter-on-terminal-quick-fixes.png 945w,
/static/da5ff20270eaeecfd4f2cecae0993655/78612/vscode-twitter-on-terminal-quick-fixes.png 1260w,
/static/da5ff20270eaeecfd4f2cecae0993655/acf8f/vscode-twitter-on-terminal-quick-fixes.png 1340w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption class=&quot;left&quot;&gt;Terminal Quick Fixes 기능을 소개하는 트윗&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;그래, 그랬구나. 그런 것이었어…&lt;/p&gt;
&lt;p&gt;코드란 원래 그런 것이다. 필요에 의해 만들어지고, 얼마간 제 역할을 한 다음, 때가 되면 사라지는 것. 문제는, 그게 나의 유일한 오픈소스 업적이었고, 제 역할을 한 시간이 너무나 짧았다는 것. 흙흙흙. 이렇게 해서 에어컨의 발명자 캐리어 님과 어깨를 나란히 해보려던 나의 가여운 소망은 가벼이 날아가버리고 말았다. (길이도) 짧았던 내 코드는 (수명도) 짧게 사라졌다.&lt;/p&gt;
&lt;p&gt;조금 아쉽지만, 뭐 그래도, 어쨌든 이렇게 이야기거리 하나는 남았다. 그러면 되었다.&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h3&gt;Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-log#Documentation/git-log.txt--Gltregexgt&quot;&gt;git-log - Show commit logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/vscode/commit/de450f991c2daa1f3207dfff4a4d7a3ffb2fd699&quot;&gt;VS Code - commit de450f991c2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/vscode/pull/160952&quot;&gt;VS Code - PR #160952&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/vscode/issues/151937&quot;&gt;VS Code - issue #151937&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/updates/v1_72#_terminal-quick-fixes&quot;&gt;VS Code release note - version 1.72&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/code/status/1578085905188913161?lang=en&quot;&gt;Tweet on Terminal Quick Fixes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[우리 동네 고양이 - part 3]]></title><description><![CDATA[(이전 글: 우리 동네 고양이 - part 2) 방법은 멀리 있지 않았다. 미키가 여태까지 쓰고 있던 AWS Amplify를 그대로 쓰면 되는 것이었다. 단, 웹 콘솔이 아니라 CLI 이용해서. “Amplify에서 frontend와 backend…]]></description><link>https://jihoon-ernesto.github.io/my-neighbor-cats-part3/</link><guid isPermaLink="false">https://jihoon-ernesto.github.io/my-neighbor-cats-part3/</guid><pubDate>Tue, 21 Dec 2021 09:25:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;(이전 글: &lt;a href=&quot;../my-neighbor-cats-part2/&quot;&gt;우리 동네 고양이 - part 2&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;방법은 멀리 있지 않았다. 미키가 여태까지 쓰고 있던 AWS Amplify를 그대로 쓰면 되는 것이었다. 단, 웹 콘솔이 아니라 CLI 이용해서.&lt;/p&gt;
&lt;p&gt;“Amplify에서 frontend와 backend 연결하는 방법 있는 것 아시잖아요? git 브랜치를 여러 개 만들 수 있듯이 backend 환경을 여러 개 만들 수 있어요. 각각의 backend 환경을 상황에 맞게 알맞은 git 브랜치에 연결해서 사용하면 돼요.”&lt;/p&gt;
&lt;p&gt;Office Hour 시간에 AWS의 W님이 해준 대답이었다. 아… 그런 것이었다. 분명히 세미나 시간에 들었던 것이지만, 역시 직접 머리를 부딪쳐봐야 알게 되는 것이었다.&lt;/p&gt;
&lt;p&gt;미키가 대충 이해한 바로는 이런 식이다. AWS 클라우드를 구성하는 방식은 여러 가지가 있을 수 있는데, 첫번째는 AWS 콘솔 웹페이지에 들어가서 마우스 클릭, 클릭, 하면서 구성하는 방식이다. Lambda 함수의 코드도 웹 화면에서 입력할 수 있다. 일단 처음 접할 때는 GUI 통해서 하는 거라 비교적 쉽게 접근할 수 있다는 장점이 있지만, 무슨 페이지 어떤 옵션에서 뭘 어떻게 했었는지 기억하기가 어렵고 여러 사람이 같이 작업하기 힘들다는 단점이 크다. 여태까지 미키와 친구들이 뚝딱뚝딱 해오고 있던 방식이었다.&lt;/p&gt;
&lt;p&gt;두번째는 로컬 PC의 터미널에서 CLI 명령어들을 입력해서 구성하는 방식이다. Amplify 서비스의 경우, &lt;code class=&quot;language-text&quot;&gt;amplify add function&lt;/code&gt; 명령으로 로컬 PC 환경에서 Lambda Function을 추가하고, &lt;code class=&quot;language-text&quot;&gt;amplify push&lt;/code&gt; 명령으로 (마치 &lt;code class=&quot;language-text&quot;&gt;git push&lt;/code&gt; 하듯이) AWS 클라우드에 올리는 방식이다. 결과적으로 클라우드 자원이 만들어지는 것은 첫번째 방식을 쓰는 것과 마찬가지이지만, 어떤 명령어를 써서 만들었는지 기록을 남기기가 더 수월하다. 사용한 터미널 명령어들을 git 커밋 메시지에 써놓기만 해도 될 테니까. 비록 터미널 창에서 텍스트 질문 답변 식으로 진행하는 게 갑갑한 느낌이 들기도 하지만, 무슨 말인지 잘 몰라서 갑갑한 걸로 치자면 웹 콘솔 페이지도 별반 차이 없으니 도긴개긴이다.&lt;/p&gt;
&lt;p&gt;게다가 Amplify CLI의 경우 결정적인 장점은 백엔드 환경을 왔다갔다하면서 작업할 수 있게 지원해준다는 것이다. &lt;code class=&quot;language-text&quot;&gt;amplify env checkout&lt;/code&gt; 명령으로 백엔드 환경 사이를 오갈 수 있고, 한 백엔드 환경에서 만든 자원은 다른 백엔드 환경 (말하자면 안정된 상태를 유지해야 하는 main 환경) 에 영향을 주지 않게 할 수 있다. 즉, main 환경 외에 dev 환경을 하나 더 만들어놓는다면, dev 환경에서 만든 DB나 Lambda 함수는 main 환경과는 별도로 관리되기 때문에 마음 놓고 이것저것 실험하고 삽질을 해도 되는 것이다. 바로 이거였다! 이런 식으로 개발 환경 구성을 해놓고 시작해야 팀 작업을 제대로 할 수 있을 것이었다.&lt;/p&gt;
&lt;p&gt;하지만, 그것도 이론적으로 좋은 것이고 그 방법론을 제대로 숙지한 상태에서 작업하는 거라면 괜찮았을 테지만, 미키와 친구들은 다들 AWS 초보… 실제로 해보니 완전히 깔끔하게 돌아가는 느낌은 아니었다. 로컬 인프라 상태를 &lt;code class=&quot;language-text&quot;&gt;amplify push&lt;/code&gt; 해서 클라우드로 올렸는데 일부 파일이 또 변경되는 경우가 있기도 하고, &lt;code class=&quot;language-text&quot;&gt;git push/pull&lt;/code&gt; 상태와 &lt;code class=&quot;language-text&quot;&gt;amplify push/pull&lt;/code&gt; 상태가 헷갈릴 때도 많고 그랬다. 뭐, 그런 것도 미키가 아직 익숙하지 않아서 미심쩍게 느낀 것일 수도 있다.&lt;/p&gt;
&lt;p&gt;*&lt;/p&gt;
&lt;p&gt;회사 옆 스타벅스는 여전히 활기가 넘친다. 코로나19 조심하느라 다들 마스크 쓰고 돌아다니고, 앉을 수 있는 자리도 이전보다 줄어들었지만 그래도 늘 북적인다. 그 무리들 중, 출입문 옆 한 구석 동그란 테이블에 미키와 W, K가 노트북 하나 놓고 옹기종기 앉아있다. 오늘은 첫번째 오프라인 모임이다. 그렇다, 이제 프로젝트 막바지를 향해 가고 있는 와중에 처음으로 얼굴을 마주하게 된 것이다.&lt;/p&gt;
&lt;p&gt;“진작에 이렇게 모였어야 하는데 죄송해요. 이제서야 뵙게 됐네요.”&lt;/p&gt;
&lt;p&gt;사실 미키로서는 W와 K에게 어느 정도로 열심히 이 프로젝트에 참여해달라고 요청해야 할지 애매하기는 했다. 각자 팀도 다르고 원래 하던 일들도 있으니, 사이드로 하는 이 작업에 미키가 무작정 푸시할 수는 없는 노릇이니까. 그래도, 기왕에 같이 하기로 한 것이었으니 조금은 더 적극적으로 연락하고 모일 필요는 있었고, 그건 미키가 살짝 놓친 점이었다.&lt;/p&gt;
&lt;p&gt;뒤늦은 첫 모임이었지만, 어쩌면 그래서 더 그랬는지도 모르지만, 다들 할 말이 많았다. 자기가 했던 삽질 자랑도 한참 하고 (서로 완전히 다 알아들은 것 같지는 않았지만…), W는 AWS 계정 로그인을 좀 더 편하게 하는 팁도 알려주고, K는 우리가 처음 계획할 때 고급 기능으로 생각해둔 Rekognition 서비스를 이용한 고양이 이미지 인식 기능을 만들어보겠다고 의욕을 보여줬다. 그래, 팀으로 같이 뭘 한다는 게 이런 거지. 따뜻한 라떼도 맛이 좋았다. 미키는 오래간만에 이런 기분을 느껴보는 것 같았다. 같이 일하는 게 재미있다, 재/미/있/다/는 느낌.&lt;/p&gt;
&lt;p&gt;*&lt;/p&gt;
&lt;p&gt;거의 다 됐다. 일주일의 시간을 더 얻은 덕분에 그래도 데모를 보여줄 수 있는 정도로는 만들어지게 되었다. 이제 K가 작업해준 고양이 인식 기능 하나만 더 붙이면 정말 좋을 것 같다. 원래 고급 기능으로 분류했던 것까지 해내는 것이니 이 얼마나 뿌듯한 일인가.&lt;/p&gt;
&lt;p&gt;Rekognition을 이용해서 고양이인지 아닌지 판별하는 것은 별도의 Lambda 함수로 구성되어 있었고, 이번에는 파이썬 대신 Node.js 로 구현되어 있었다. 이미지 파일 저장용 S3 버킷에 새 사진이 업로드되면 이 판별 함수가 실행되도록 하면 되었는데, 그러려면 시스템 연동 경로를 약간 수정해야 했다. 고양이 판별용 Lambda 함수 말고 그 전에 W가 만들어준 썸네일 생성용 Lambda 함수도 있었는데, 그 두 Lambda 함수 모두 S3 버킷의 새 이미지 업로드 이벤트를 트리거로 삼아 반응해야 하는 것이었다. 하지만 S3 버킷에서 직접 이벤트를 받는 것은 단 하나의 Lambda 에서만 가능했기 때문에, 다른 연결 방식이 필요했다.&lt;/p&gt;
&lt;p&gt;미키는 SNS(Simple Notification Service)를 사용하기로 했다. S3 버킷의 이미지 업로드가 &lt;code class=&quot;language-text&quot;&gt;cat-photo-uploaded&lt;/code&gt; 라는 SNS 토픽을 발생시키도록 하고, 이 토픽을 두 개의 Lambda 함수에서 받아서 각각 자기 할 일을 하는 거다. 하나는 원본 이미지로부터 썸네일 이미지를 생성해서 따로 저장해두고, 다른 하나는 원본 이미지를 살펴보고 고양이 사진인지 아닌지를 판별한 다음 DB에 결과를 쓰는 거다. 이거 고양이 맞음, 또는 고양이 아님.&lt;/p&gt;
&lt;p&gt;Amplify CLI 에서 곧바로 SNS topic을 생성할 수 있으면 좋을 텐데, 미키는 CLI에서는 딱 맞는 방법을 찾지는 못했다. &lt;code class=&quot;language-text&quot;&gt;amplify add notifications&lt;/code&gt; 명령으로 할 수 있을 줄 알았는데, 지금 사용하려는 상황에 맞는 걸 생성하는 방법은 아닌 것 같았다. Amplify CLI가 커버할 수 있는 영역이 한정되어 있다고 들었는데 어쩌면 이것도 그런 것일지도 몰랐다. 가능한 한 모든 것을 기록으로 남기고 싶었는데… 미키는 약간 아쉬운 마음이 들었다. 제대로 이력을 남기면서 클라우드 인프라 관리를 하려면 CDK 같은 본격적인 IaC(Infra as Code) 도구를 함께 써야 하는 것 같았다.&lt;/p&gt;
&lt;p&gt;좋아, 일단은 되게 해야지. 웹 콘솔에서 추가하고, S3 버킷과 두 Lambda 사이를 연결해주었다. Lambda의 입력으로 들어오는 이벤트 개체의 형식이 달라졌으니 그 부분들의 코드도 살짝 수정해주고. 이제 AWS에 약간은 익숙해진 것이었을까? 미키는 이제 어찌어찌 대충 구현하는 건 그럭저럭 할만하다고 느꼈다. “다 필요 없고요. 일단 돌아가게 만들어보세요.” AWS I 님의 메시지는 프로젝트 기간 내내 마치 요다의 메시지처럼 미키의 머리 속을 맴돌고 있었다. &lt;em&gt;다 필요 없고요… 다 필요 없고요…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;그런데 아직 하나가 해결이 안 되고 있었다. 고양이 판별 결과를 DB에 남겨야 하는데, DynamoDB에 접근해서 쓰는 게 잘 안 되고 있었다. 로그를 찍는 코드를 넣었는데도, CloudWatch에 아무 로그도 남지 않고. 어떻게 된 거지?&lt;/p&gt;
&lt;p&gt;일요일 오후였다. 이제 구현 작업은 마무리를 하고, 발표 자료를 만들어야 할 시점이었다. 가족들은 밖에서 문을 두드리고 있었다. &lt;em&gt;“Do you wanna build a snowman?”&lt;/em&gt; 아니 그건 아니고. 하여튼 얼마간을 끙끙댄 미키는 약간, 그만 하고 싶다는 생각도 들었다. ‘이건 그냥 뺄까..?’ 있으면 좋지만 없어도 뭐, 큰 지장이 있는 건 아닌 기능이었으니까. 하지만 미키는 곧 머리를 흔들었다. 아냐, 이건 분명히 별 거 아닌 걸 몰라서 헤매고 있는 걸 거야. 이런 걸 해결 못해서 멈추면 너무 아깝지.&lt;/p&gt;
&lt;p&gt;그리고 안타깝게도, 미키가 맞았다. DB에 접근하는 코드는 어쩌면 당연히 비동기로 동작하도록 해야 하는데, 그 구현을 제대로 안 했기 때문에 DB 관련 동작을 제대로 수행하기도 전에 Lambda 함수가 종료되어 버린 것이었고, 따라서 로그조차도 남지 않았던 것이었다. 이런… 미키는 몹시 부끄러운 생각이 들었다. 명색이 JavaScript 개발자라고 하면서 Promise 비동기 코드도 제대로 못 짜서 이렇게 헤매다니. 내가 이런 걸 잘 몰라서 헤맸다는 건 아무한테도 얘기하지 말아야지. 남부끄러운 일이니까. 암, 그렇고말고. 절대 말 안 할 거야.&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/23c5ae3b497c73e0aabaecbe8f956ae2/89048/my-neighbor-cats-screenshot-1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 177.8481012658228%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,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&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;스크린샷-1&quot;
        title=&quot;&quot;
        src=&quot;/static/23c5ae3b497c73e0aabaecbe8f956ae2/f058b/my-neighbor-cats-screenshot-1.png&quot;
        srcset=&quot;/static/23c5ae3b497c73e0aabaecbe8f956ae2/c26ae/my-neighbor-cats-screenshot-1.png 158w,
/static/23c5ae3b497c73e0aabaecbe8f956ae2/6bdcf/my-neighbor-cats-screenshot-1.png 315w,
/static/23c5ae3b497c73e0aabaecbe8f956ae2/f058b/my-neighbor-cats-screenshot-1.png 630w,
/static/23c5ae3b497c73e0aabaecbe8f956ae2/40601/my-neighbor-cats-screenshot-1.png 945w,
/static/23c5ae3b497c73e0aabaecbe8f956ae2/89048/my-neighbor-cats-screenshot-1.png 1242w&quot;
        sizes=&quot;(max-width: 630px) 100vw, 630px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2060dab1402d7b714668674a236acb99/89048/my-neighbor-cats-screenshot-2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 177.8481012658228%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,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&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;스크린샷-2&quot;
        title=&quot;&quot;
        src=&quot;/static/2060dab1402d7b714668674a236acb99/f058b/my-neighbor-cats-screenshot-2.png&quot;
        srcset=&quot;/static/2060dab1402d7b714668674a236acb99/c26ae/my-neighbor-cats-screenshot-2.png 158w,
/static/2060dab1402d7b714668674a236acb99/6bdcf/my-neighbor-cats-screenshot-2.png 315w,
/static/2060dab1402d7b714668674a236acb99/f058b/my-neighbor-cats-screenshot-2.png 630w,
/static/2060dab1402d7b714668674a236acb99/40601/my-neighbor-cats-screenshot-2.png 945w,
/static/2060dab1402d7b714668674a236acb99/89048/my-neighbor-cats-screenshot-2.png 1242w&quot;
        sizes=&quot;(max-width: 630px) 100vw, 630px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure&gt;
  &lt;figcaption&gt;그런데 넌 왜 고양이가 아닌 거니...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;발표는 잘 진행되었다. W, K와 공동 편집한 발표 자료를 가지고 데모도 간단히 잘 보여주고, 처음 설계와 달라진 점들, 또 그동안 작업을 하면서 삽질했던 내용들을 소개했다. 그리고, 테스트하면서 발견한 치명적인 결함도 소개했다.&lt;/p&gt;
&lt;p&gt;“이거, 이 문제 해결 안 되면 사업 접어야 해요!”&lt;/p&gt;
&lt;p&gt;미키의 이 말에 다들 즐거워(?)했다. 아이폰 사파리에서 실행되는 웹 앱의 경우, 사진을 업로드하면 사진 안에 있는 위치 정보가 삭제되는 문제가 있었던 것인데, 개인정보 보호 이슈 때문에 브라우저에서 강제로 그렇게 하는 모양이었다. 그런데 위치 정보가 없으면 동네 지도에 표시를 할 수 없으니 이 서비스 자체가 구성될 수 없었다.&lt;/p&gt;
&lt;p&gt;하여튼 이런저런 이슈들과 향후의 과제 등에 대해서도 소개하였고, 프로젝트 처음 시작할 때의 주제 발표 시간에 그랬던 것처럼 많은 관심과 뜨거운 반응을 얻었다. 발표 후에 자료를 이메일로 공유했을 때도 AWS SA 분들이 다들 감사 인사와 함께 열렬히 추가 정보 - 위치 정보 삭제 문제에 대한 해법도 포함해서! - 를 제공해주셔서 미키는 정말 고마운 마음이 들었다. 어찌 보면 별 거 아닌 데모 프로젝트, 혹은 실습 과제 정도일 뿐이지만 그냥 이렇게 끝내고 말기에는 너무 아깝다는 생각이 들었다. 뭐라도 흔적을 남겨야겠어. 가령, 하다못해 블로그 글 한 편이라도… 제목은 뭘로 할까? “본격 웹 개발 프로젝트: 우리 동네 고양이” 이런 건 어때. 아냐, 너무 거창해, 하나도 본격적이지 않은데. 그냥 “우리 동네 고양이”가 좋겠어. 단순하고, 아름답고, 완벽해. 미키는 괜시리 마음이 설레었다.&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/db7e019665a15c0b73d03ac5b1c3daa9/a0730/my-neighbor-cats-arch-v1.2.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 62.0253164556962%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAACK0lEQVR42n2TS2/TQBSF/S9ZwYYfwh513R1igYQA8VA3bVWERGkLolIfqvqIkpCnmzh2/IidcewZjz+YIaRpF1xpNPa9mnvOPXPGAajr2my83Nphb/MF6ZOnuF/3iYRgvX4vljkxc2mebdG93mPS2sYxSa21LV4025zvH+C9+0jc6yOKwh6UUjIcDQjDKb7vU5r8MhbpkKCzQxn+ZDHexTHoZVlSVZVlUpQlpdYWpDILKGRBa3xDPA/XGP9lqAsfnZ5Cfo2cHuIY9GKJmC1SRJlRqwpda2qpIMqgqihkjtQ1tXtOkUzIRE6e50sAQ0BR1xVOFCeMPR8lFa4/YOD3qEqFpEactPAebZBfD8grSSE1urFL5jaYhDELIbhNIjrTyUoCZzQa43meHSPwA7qdrpXARHo7ofHmM0U4s/+qBt05QLhXxKmw+h41LjnttldSOGEYkmUZqtLEocfVlw2UylFBB937jrmuWks+HTUZBHN0KahkuWJkyARBcMfQaCiVtJcyi6acH72nLBeQR+TDS/q9vpGeV3sX3PQDur/auLejBw6qV9ZylJJWTNNQiBzPjxH5whYNWBzHKKWYpwlinuEHgc2tN7rX8Li5zYV7THBySNLu3Nni31pnscYqKRRCVdSVQlfybuQP3x6zc/qM7uZzWq/fWt+xNPrDsZZftvGPcUIjXiDTEBGNV9jOdHSGmLVx+wO84fDes/pfzLPUuiGKQvr9HtJ49k/D3/Jjkw8xoYUhAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;changed-architecture&quot; title=&quot;&quot; src=&quot;/static/db7e019665a15c0b73d03ac5b1c3daa9/f058b/my-neighbor-cats-arch-v1.2.png&quot; srcset=&quot;/static/db7e019665a15c0b73d03ac5b1c3daa9/c26ae/my-neighbor-cats-arch-v1.2.png 158w,
/static/db7e019665a15c0b73d03ac5b1c3daa9/6bdcf/my-neighbor-cats-arch-v1.2.png 315w,
/static/db7e019665a15c0b73d03ac5b1c3daa9/f058b/my-neighbor-cats-arch-v1.2.png 630w,
/static/db7e019665a15c0b73d03ac5b1c3daa9/40601/my-neighbor-cats-arch-v1.2.png 945w,
/static/db7e019665a15c0b73d03ac5b1c3daa9/a0730/my-neighbor-cats-arch-v1.2.png 1131w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;프로젝트 구조 - 구현하면서 달라진 설계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;*&lt;/p&gt;
&lt;p&gt;이제 해가 뉘엿뉘엿 넘어가고 있다. 오늘도 좋은 날이었다. 더운 열기는 여전하지만 그 사이로 한줄기 시원한 바람이 지나갈 때가 있다. 어느 새, 계절이 모습을 바꾸고 있는 게 느껴진다.
저쪽에서 누가 오고 있다. 지난 번 이후로 종종 찾아오던 싱거운 휴먼, 미키다. 이젠 내 친구라도 된다는 듯이 씩 웃으면서 사뭇 당당하게 휴대폰을 꺼낸다. 약간 어이가 없다. 딴 데로 자리를 옮겨야겠다.&lt;/p&gt;
&lt;p&gt;“어…”&lt;/p&gt;
&lt;p&gt;미키는 좀 당황하는 것 같다. 알 게 뭐람.&lt;/p&gt;
&lt;p&gt;“바둑아, 고마워! 잘 지내~!”&lt;/p&gt;
&lt;p&gt;도대체 뭐래는 거야. 울타리 위로 뛰어올랐다. 사뿐사뿐 동네 산책이나 하고 와야겠다. 어디선가 좋은 냄새가 난다.&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;&lt;em&gt;The End&lt;/em&gt;&lt;/p&gt;
&lt;figure style=&quot;max-width:320px&quot;&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/7f086c6c218065601763f4b468341578/212bf/cat-back.jpg&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 133.54430379746836%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAMBAgUE/8QAFwEBAQEBAAAAAAAAAAAAAAAAAQACA//aAAwDAQACEAMQAAABVx6iOTYgBWplU0XElf/EAB0QAAICAgMBAAAAAAAAAAAAAAECABEQEwMSISL/2gAIAQEAAQUCHWMvpNYtNjEXsqKOOimCfqf/xAAXEQADAQAAAAAAAAAAAAAAAAAAEBEh/9oACAEDAQE/AYYVf//EABcRAAMBAAAAAAAAAAAAAAAAAAABEBH/2gAIAQIBAT8BRl//xAAaEAACAwEBAAAAAAAAAAAAAAABEQAQMRIh/9oACAEBAAY/AshmUiWaxmdIdLZ7Sr//xAAdEAEAAwADAAMAAAAAAAAAAAABABEhMUFhUXGB/9oACAEBAAE/Ie1WTGOLmauncT2P5AReIvj8BTCXllaprkTND7Bd+4xQtRn/2gAMAwEAAgADAAAAEOfIfv/EABoRAAICAwAAAAAAAAAAAAAAAAARARAhQVH/2gAIAQMBAT8QWNi6IwVf/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERIf/aAAgBAgEBPxBoyRYQ/8QAIBABAAICAgEFAAAAAAAAAAAAAQARITFBUWFxgZHB0f/aAAgBAQABPxDCANqXDEr0oT0loYUab4+pQCBe+PiDwSW6EtiAruY6wasPLXLDLTCoajjR7QzpWlTHCvP7lVJbBicZ4n//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;뒷모습-고양이&quot; title=&quot;&quot; src=&quot;/static/7f086c6c218065601763f4b468341578/828fb/cat-back.jpg&quot; srcset=&quot;/static/7f086c6c218065601763f4b468341578/ff44c/cat-back.jpg 158w,
/static/7f086c6c218065601763f4b468341578/a6688/cat-back.jpg 315w,
/static/7f086c6c218065601763f4b468341578/828fb/cat-back.jpg 630w,
/static/7f086c6c218065601763f4b468341578/212bf/cat-back.jpg 768w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;/figure&gt;
&lt;h3&gt;Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hnc-jihoon/my-neighbor-cats&quot;&gt;우리 동네 고양이 프로젝트 저장소&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Thank you&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;함께 프로젝트에 참여해준 &lt;a href=&quot;https://github.com/hnc-kaisin&quot;&gt;W님&lt;/a&gt;과 &lt;a href=&quot;https://github.com/hnc-keonwookim&quot;&gt;K님&lt;/a&gt;에게 감사의 인사를 전합니다.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;이 글은 아직 공사중인 다른 블로그 사이트에 먼저 쓴 글입니다. 그 사이트가 공개되면 출처를 남기겠습니다.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[우리 동네 고양이 - part 2]]></title><description><![CDATA[(이전 글: 우리 동네 고양이 - part…]]></description><link>https://jihoon-ernesto.github.io/my-neighbor-cats-part2/</link><guid isPermaLink="false">https://jihoon-ernesto.github.io/my-neighbor-cats-part2/</guid><pubDate>Thu, 25 Nov 2021 10:40:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;(이전 글: &lt;a href=&quot;../my-neighbor-cats-part1/&quot;&gt;우리 동네 고양이 - part 1&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;“내 이럴 줄 알았어…”&lt;/p&gt;
&lt;p&gt;미키는 집에서 야근 중이다. 재택 근무의 장점은 작업의 흐름을 끊지 않고 쭉 이어서 밤까지 달릴 수 있다는 점이다. &lt;del&gt;(장점 맞지?)&lt;/del&gt; 물론 거기에 식구들의 원성과 미안한 마음을 보너스로 곁들인… 그래도 오늘은 이것까지는 해야만 할 것 같다. 프론트엔드와 백엔드를 연결해서, 서버로부터 받아온 데이터를 가지고 화면에 보여주도록 할 단계이다. 서버가 보내줄 데이터도 아직은 샘플 이미지에 불과하지만, 그래도 이만큼은 해놔야 고맙게도 백엔드 작업을 척하니 해결해준 W에 대한 응답이 될 수 있을 것이었다.&lt;/p&gt;
&lt;p&gt;무식하면 용감하다고, 백엔드를 잘 몰랐던 미키는 그냥 뭐, 해야 하면 어떻게든 대충 만들면 되겠지 하는 생각이었다. 그런데 W가 작업해준 DynamoDB와 Lambda 내용을 보니 그게 아니었다는 생각이 들었다. 분량이 많은 것은 아니었지만, 미키 혼자 맨땅에 헤딩하면서 했으면 많이 고생했을 것 같았다. 딱 적절한 타이밍에 DB 기초 설계와 API 처리 코드가 준비되어서 다행이었다. 자, 이제 내 차례군, 나만 잘 하면 돼. 미키는 생각했다. 그러니 연동만 잘 하면 되는데, 그래 이런 게 한번에 될 리가 없지. 미키는 그럴 줄 알았다는 듯 고개를 좌우로 흔들었다.&lt;/p&gt;
&lt;p&gt;AWS에 대해서 모를 때는, 그저 물리적인 서버를 가상으로 만들어주는 서비스 정도로만 생각했다. 하지만 알고 보니 그건 단지 전체 AWS 서비스의 일부분일 뿐이었고(EC2 라는 이름이었다), AWS 안에는 정말 수백 가지의 서비스가 다양한 요구사항에 맞도록 만들어져 있었다. 그리고 그 서비스들은 또 수많은 옵션과 설정값에 따라 동작 방식을 다르게 만들 수 있어서, 잘 모르고 들어갔다가는 너무 많은 선택지들 사이에서 길을 잃게 되기 십상이었다. 미키가 바로 지금 그렇게 허우적거리고 있는 중이었다.&lt;/p&gt;
&lt;p&gt;“왜 대답이 없니, 왜. 콜을 했으면 대답을 해야 할 것 아니니…”&lt;/p&gt;
&lt;p&gt;AWS Amplify 서비스를 이용해서 전반적인 구성을 하였고, DynamoDB와 Lambda, 그리고 그 앞의 API Gateway가 백엔드의 주요 축이었다. 프론트엔드 쪽에서 고양이 목록 정보를 요청하면 API Gateway가 요청을 받고 serverless Lambda 함수가 실행되어 DynamoDB에 저장된 정보를 훑어서 사진의 URL 등을 모아서 보내주는 식이었다. 고양이 사진들은 S3 버킷에 미리 몇 장 올려둔 상태였다. 그런데 프론트엔드의 POST 메시지에 제대로 응답이 돌아오지 않는 게 문제였다.&lt;/p&gt;
&lt;p&gt;사실 이런 건 잘 되어야 하는 일이었다. 오리는 꽥꽥. 돼지는 꿀꿀. 요청에는… 무응답? 잘 될 때는 쉽고 자연스럽고 당연한 것이지만, 안 될 때는 또 그만큼 답답하다. 제대로 된 응답이 만들어지기까지의 여러 과정 중에서 하나만 삐끗해도 실패하는 것이기에 여기저기 다 찔러봐야 하고, 때로는 어디 가서 물어보기에도 좀 창피한 경우도 있고 그렇다.&lt;/p&gt;
&lt;p&gt;결국 미키는 그 밤을 활활… 까지는 아니지만 살짝 불살라야만 했다. CloudWatch 들어가서 로그도 살펴보고, Lambda 서비스 안에 있는 테스트도 돌려보고, API Gateway 쪽에 있는 테스트도 점검해보면서. 결국 API Gateway의 Lambda Proxy 설정을 조정하고, Lambda 함수에서 생성하는 응답을 json 형식으로 묶어주고, 숫자 형식으로 다루던 위도/경도 값을 문자열 형식으로 전달해주도록 바꾸는 등의 작업을 한 다음에야 비로소 원하는 결과를  볼 수 있었다. 이제 드디어, 참새는 짹짹. 요청에는 응답.&lt;/p&gt;
&lt;figure style=&quot;max-width:500px&quot;&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/c56c2b9ce791bc72c8bacd8c6f6e40c6/e0c5a/cat-on-the-rock.jpg&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 74.68354430379746%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMBAgT/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/2gAMAwEAAhADEAAAASFaiQVMH//EABsQAAICAwEAAAAAAAAAAAAAAAECESEAAxIx/9oACAEBAAEFApGKQWItfOp1s9//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARL/2gAIAQIBAT8BjT//xAAZEAACAwEAAAAAAAAAAAAAAAAAAREhMUH/2gAIAQEABj8CK0wtSN9RR//EABoQAQADAQEBAAAAAAAAAAAAAAEAESExgUH/2gAIAQEAAT8hfg+TBOKWOph0z2RAdUZkUfA7yf/aAAwDAQACAAMAAAAQ9P8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAEDAQE/ELWv/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARMf/aAAgBAgEBPxAabJHl/8QAHRABAAICAgMAAAAAAAAAAAAAAQARIUExUYGR8P/aAAgBAQABPxCtwdIzHKaMxVnxzFYR3XfuUguwLazbKHt/dhN14qLZsYBec7n/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;바위-고양이&quot; title=&quot;&quot; src=&quot;/static/c56c2b9ce791bc72c8bacd8c6f6e40c6/828fb/cat-on-the-rock.jpg&quot; srcset=&quot;/static/c56c2b9ce791bc72c8bacd8c6f6e40c6/ff44c/cat-on-the-rock.jpg 158w,
/static/c56c2b9ce791bc72c8bacd8c6f6e40c6/a6688/cat-on-the-rock.jpg 315w,
/static/c56c2b9ce791bc72c8bacd8c6f6e40c6/828fb/cat-on-the-rock.jpg 630w,
/static/c56c2b9ce791bc72c8bacd8c6f6e40c6/0ede0/cat-on-the-rock.jpg 945w,
/static/c56c2b9ce791bc72c8bacd8c6f6e40c6/3ac88/cat-on-the-rock.jpg 1260w,
/static/c56c2b9ce791bc72c8bacd8c6f6e40c6/e0c5a/cat-on-the-rock.jpg 2049w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;/figure&gt;
&lt;p&gt;미키는 그 다음에도 몇 개의 징검다리를 더 건너야 했다. K가 작업해준 Cognito를 통한 사용자 sign up/sign in 프로세스를 붙이는 일도 했다. 회원 가입과 로그인 처리하는 걸 직접 만들려면 상당히 품이 많이 드는 일일 텐데, Cognito 이용하니 비교적 쉽게 그런 걸 할 수 있었다. 그래, 이런 서비스를 다 갖추어놓았으니 AWS가 돈을 버는 것이겠지.&lt;/p&gt;
&lt;p&gt;고양이 사진에 들어있는 위치 정보를 뽑아내는 일도 필요했다. 그 일을 해주는 파이썬 라이브러리를 어렵지 않게 찾을 수 있었는데, 문제는 그걸 Lambda 함수에서 실행하는 문제였다. 뒷골목 돌 때마다 마주치게 되는 dependency 문제.&lt;/p&gt;
&lt;p&gt;파이썬을 잘 모르는 미키였지만 - 어릴 때 본 책에 나온 ‘왕뱀 퓌톤’ 이란 명칭을 떠올리며 싱겁게 웃기나 하는 정도였다 - 어쨌든 필요한 라이브러리들을 끼워넣어야 했다. 뭐가 없네, 또 뭐가 없네, 하는 에러 메시지들마다 적당히 끼워 맞춰서 의존성 문제를 해결하는 중이었는데, PIL이라는 라이브러리가 문제였다.&lt;/p&gt;
&lt;p&gt;이미지 처리를 위해서 쓰는 라이브러리인가본데, 요즘은 그걸 fork한 pillow 라는 걸 쓰는 모양이었다. 근데 그걸 &lt;code class=&quot;language-text&quot;&gt;pipenv install&lt;/code&gt; 해서는 설치가 잘 안 되고 뭔가 다른 방법으로 해야 하는 것 같았는데, 구글링해보니 어떤 용자가 Lambda Layer 들을 미리 만들어서 그 ARN(Amazon Resource Name)을 공개해놓은 것이 있었다. 그러니까 내가 원하는 라이브러리를 갖고 있는 Lambda Layer를 내 Lambda 함수 아랫단에 끼워넣으면 의존성이 해결되는 것이었다. 여러 개의 Lambda 함수에서 공통으로 사용할 코드를 Layer로 만들면 된다고 배웠는데, 이런 식으로도 사용할 수 있는 것이었군. 어쨌든 방법을 찾아서 다행이다, 미키는 한숨 돌리며 생각했다.&lt;/p&gt;
&lt;p&gt;그런데 꼭 이렇게밖에 할 수 없는 걸까? AWS에서 파이썬 쓰는 게 썩 부드럽지는 않군. 미키는 엊그제 개발환경으로 Cloud9을 써볼까 싶어서 한번 시도해봤었는데, 거기서도 파이썬 버전 문제 때문에 그만둔 적이 있었기 때문이다. Lambda 함수에서 생성할 때 기본 지정되는 파이썬 런타임의 버전은 3.8인데, Cloud9에서 t3 AMI(Amazon Machine Image) 지정해서 인스턴스를 생성하면 파이썬 3.7이 들어 있다. 버전을 올려서 사용하고 싶으면 수동 설치하면 되긴 된다는데, 그러려면 먼저 인스턴스의 디스크 용량을 확장해야 한단다. 으… 미키는 거기까지 해보다가 귀찮아서 포기했다.&lt;/p&gt;
&lt;p&gt;사실 Cloud9을 쓰게 되면 브라우저 상에서 코딩을 하게 될 텐데, 데스크탑 VS Code의 친숙함에 익숙해진 상태에서 브라우저 환경을 잘 쓰게 될지도 미지수인 상황이었다. 게다가 파이썬 버전을 맞추기 위해 이런 귀찮은 일까지 해야 한다면, 그다지 매력은 없었다. 어떤 서비스를 쓰든 동일한 버전을 사용할 수 있도록 AWS 쪽에서 일괄적으로 관리를 해주어야 불편함 없이 쓸 수 있을 것이었다. 하지만, 개발 언어로서 ‘왕뱀 퓌톤’은 나름 매력적인 간결함을 가지고 있는 것 같았다. 다음에 또 기회가 되면 좀 더 배워서 써봐야겠다고 미키는 생각했다.&lt;/p&gt;
&lt;figure style=&quot;max-width:500px&quot;&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/62b3ed75348059f39861f4cbade78ea1/e0c5a/cat-on-the-grass.jpg&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 74.68354430379746%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAQACA//EABUBAQEAAAAAAAAAAAAAAAAAAAAD/9oADAMBAAIQAxAAAAHsO4CY/8QAFxAAAwEAAAAAAAAAAAAAAAAAAAERAv/aAAgBAQABBQJOq50QhFD/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwGI/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEh/9oACAECAQE/AcR//8QAGRAAAgMBAAAAAAAAAAAAAAAAAAEQITGB/9oACAEBAAY/AimnGGLkf//EABwQAQACAQUAAAAAAAAAAAAAAAEAERAxQVFhcf/aAAgBAQABPyELAhsI4wCiOqVii8VA6n//2gAMAwEAAgADAAAAEOMP/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAx/9oACAEDAQE/EAOR/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARMf/aAAgBAgEBPxAFy1f/xAAcEAEBAQEAAgMAAAAAAAAAAAABEQBBITFRgcH/2gAIAQEAAT8QKQPaenuIW4iyzHzXDIOweYaKhKFH7vAW/ub/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;풀밭-고양이&quot; title=&quot;&quot; src=&quot;/static/62b3ed75348059f39861f4cbade78ea1/828fb/cat-on-the-grass.jpg&quot; srcset=&quot;/static/62b3ed75348059f39861f4cbade78ea1/ff44c/cat-on-the-grass.jpg 158w,
/static/62b3ed75348059f39861f4cbade78ea1/a6688/cat-on-the-grass.jpg 315w,
/static/62b3ed75348059f39861f4cbade78ea1/828fb/cat-on-the-grass.jpg 630w,
/static/62b3ed75348059f39861f4cbade78ea1/0ede0/cat-on-the-grass.jpg 945w,
/static/62b3ed75348059f39861f4cbade78ea1/3ac88/cat-on-the-grass.jpg 1260w,
/static/62b3ed75348059f39861f4cbade78ea1/e0c5a/cat-on-the-grass.jpg 2049w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;/figure&gt;
&lt;p&gt;자, 이제 보니 그래도 어느 정도 와꾸(?)는 잡혀가는 것 같았다. 그런데, 계속 이런 식으로 작업해도 되는 걸까? 뭔가 중요한 걸 빠뜨리고 있다는 생각이 미키의 뒤통수를 치고 지나갔다. 이걸 지금 나 혼자 하고 있는 게 아니잖아. 셋이 같이 만들고 있는 건데, 누가 열심히 꾸며놓은 인프라 설정을 다른 사람이 새 작업을 하다가 바꿀 수도 있는 거잖아. 그러다가 누가 또 다시 갑자기 원래대로 돌려놓을 수도 있는 거고. 사실 그건 미키 혼자 작업을 한다 해도 마찬가지였다. 현재의 안정된 세팅 상태를 유지하면서, 동시에 새로운 개발 작업을 하려면 어떻게 해야 하지?&lt;/p&gt;
&lt;p&gt;말하자면 백엔드의 개발 프로세스를 어느 정도는 제대로 갖춰놓아야 할 필요가 있었다. 실습 시간에 예제 코드 copy &amp;#x26; paste 하면서 인프라 꾸미는 것과는 다른 방식이 필요했다. 하루 이틀 만들어보고 날려버릴 연습문제 푸는 게 아니잖아, 미키는 중얼거렸다. 질문 메일을 써야겠군. 다음 번 Office Hour 때 AWS SA 분들이 와서 답을 해줄 수 있도록 메일을 작성했다.&lt;/p&gt;
&lt;p&gt;“저기요, 백엔드 인프라 설정을 git 소스 코드에 같이 저장해서 관리하려면 어떻게 해야 하나요? 얼핏 보니 CodeStar 라는 서비스도 있던데 그런 걸 이용하면 할 수 있는 건가요?”&lt;/p&gt;
&lt;p&gt;물론 미키가 실제로 저렇게 쓴 건 아니었다. 어쨌든 중요한 포인트를 한발 뒤늦게 짚은 것 같았다. 주어진 프로젝트 기한은 이제 중반을 넘어가고 있었다.&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;&lt;em&gt;(이어지는 글: &lt;a href=&quot;../my-neighbor-cats-part3/&quot;&gt;우리 동네 고양이 - part 3&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/keithrozario/Klayers&quot;&gt;Keith’s Layers (Klayers)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;이 글은 아직 공사중인 다른 블로그 사이트에 먼저 쓴 글입니다. 그 사이트가 공개되면 출처를 남기겠습니다.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[우리 동네 고양이 - part 1]]></title><description><![CDATA[…]]></description><link>https://jihoon-ernesto.github.io/my-neighbor-cats-part1/</link><guid isPermaLink="false">https://jihoon-ernesto.github.io/my-neighbor-cats-part1/</guid><pubDate>Tue, 02 Nov 2021 02:17:00 GMT</pubDate><content:encoded>&lt;p&gt;오늘은 볕이 좋다. 사실은 좋은 정도를 넘어서 너무 쨍하다. 뜨거운 계절 한가운데를 지나고 있는 중이니까. 그나마 한낮의 열기가 살짝 가시고 나니 좀 낫다. 놀이터에는 그네 타는 어린이들, 같이 온 어른들, 산책 나온 노인들, 시끄러운 중고딩들이 늘 자리를 채운다. 어떤 이들은 잠시 지나쳐 가고, 다른 이들은 한참 동안 죽치고 앉아있기도 한다. 아는 얼굴도 있고 모르는 얼굴도 있다. 방금 들른 어떤 아저씨처럼 괜히 친한 척을 하는 사람도 있다.&lt;/p&gt;
&lt;p&gt;“안녕?”&lt;/p&gt;
&lt;p&gt;반바지에 파란색 미키마우스 티셔츠를 걸친, 좀 철없어보이는 사내가 말을 건다. 하지만 낯선 이에게 함부로 대답할 일은 아니다. 미키는 부시럭거리며 휴대폰을 꺼내더니 찰칵, 찰칵 소리를 낸다. 그러더니 씨익 한번 웃고는 바이바이 손 한 번 흔들고 겅중겅중 가버린다. 끌끌끌… 휴먼, 너도 참 싱거운 족속이구나. 볕 좋은 바위 위에 한참 앉아있었더니 배가 따땃해졌다. 이제 입에 뭘 좀 넣어볼까? 저만치 떨어진 벤치에는 학교 끝난 아이들이 재잘대며 아이스크림을 먹는 중이다.&lt;/p&gt;
&lt;p&gt;“야옹아~!”&lt;/p&gt;
&lt;p&gt;아, 저기 온다. 빨강바지 아주머니가 오늘도 어김없이 먹을 걸 들고 오시는 중이군. ㅎㅎㅎ 이제 슬슬 움직여볼까. 하품 한번 하고, 기지개도 쭉 펴고.&lt;/p&gt;
&lt;p&gt;*&lt;/p&gt;
&lt;p&gt;미키는 약간 초조하다. 지금쯤이면 어느 정도 와꾸(?)가 잡혀야 하는데, 여전히 초기 단계에서 헤매고 있다. 어쨌든 뭔가 빈 껍데기라도 눈에 보이는 게 있어야 그 다음 진도를 나갈 수 있을 것 같은데, 썰렁한 지도 한 장 띄우는 것도 그냥 한번에 되는 건 아니었다. 끌끌.&lt;/p&gt;
&lt;p&gt;그래도 같이 하겠다고 손들어준 W와 K가 있어 다행이었다. 사실 이 주제를 AWS 프로젝트(AWSome Builder Program, ABP라고 불리고 있었다) 그룹 채팅방에 소개했을 때, 약간 걱정이 되기도 했었다. 동네 길고양이 지도 서비스를 만든다고? 거 참 실속없다 얘, 하고 누군가 코웃음칠 것 같았다. 하지만 의외로 반응이 괜찮았다. W는 즉각 합류 의사를 밝혀왔고, K는 별도의 주제를 고민하다가 이쪽에 힘을 보태주기로 했다. 주제 및 설계 초안 발표 모임 전날, K의 설계 스케치 덕분에 미키는 그걸 바탕으로 문서를 완성하고 잘 발표할 수 있었다.&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/787363958f7208cc6ea43bbf8cf55974/7bf07/my-neighbor-cats-arch-v1.1.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 70.25316455696203%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAACZUlEQVR42o2Sy2/TQBCH80cjIXHuBST+AC4VNxCilVCBUyt6aIsUkbSUhpCmr6R5OPH7kbW96/WHdt2GHopgrNGud+xvfjM7LYD+8IrNN9t8dAqOvZU5wn+1SfL0GWura8zz57XZh8shw+879DsfiGbfaJnDqbPk8+4+uyOX86ABTt6+5/r5S7vXdc3tfIQfeLiuR1EUa3DqDXAuPpHO9tHJSQM0lqUpIomQZUlZlnhRyNhxkKVE5IKxe0WY+dS6RmttNDbJ8lvquA1ZB7IzWiYopSQvCvJCkIQLiiK3UCWlVWM8SF1EsbKcqqpQSt7VXkKVUqsMtKDlej7TmYNUmtlNj/b2EwqRIETOSgiEEKRZyrVzgRsuCfyALMtQSq37+NBa0+mU2Wxmes58NuFH92CdvdZVU5bWZElMkQukbEB/BZpsqemfELb0JMnIywodz6lvDshVjZYFr3d/cnIxZzjoE0aRLftR4L0CA6yUaryGeHnL/PSL7aNWknd7x5xdTAgDD5Hn/wc0qxmRWmuSdMXE8dC6RmmJrkqkLO27gZlLe8ws0KjKlcLr9ZgfHtqAVBIpSnwd8WK+Q2b+L1LqaNTEzWTkue2lEWJW443CqsJcw/nWFqcbG4iisCrSOCUWEXuDMZOFJIuWTK/6FhaGIZeXlziOw3K5JAgCVqtVA7zvhe/7jEeNApPNzJ+SCmfhEKehveEgim3cdV06nQ7dbte6gZrvWw/rN2B9B7ejkqascsFW5yuTwFufG1ssFhwdHdFut+n3+4zHY6uyxT9MKkVv8MuO1sNqzLiZkkejkYWb0qMo4jdoGS4eMY0olgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;initial-architecture&quot; title=&quot;&quot; src=&quot;/static/787363958f7208cc6ea43bbf8cf55974/f058b/my-neighbor-cats-arch-v1.1.png&quot; srcset=&quot;/static/787363958f7208cc6ea43bbf8cf55974/c26ae/my-neighbor-cats-arch-v1.1.png 158w,
/static/787363958f7208cc6ea43bbf8cf55974/6bdcf/my-neighbor-cats-arch-v1.1.png 315w,
/static/787363958f7208cc6ea43bbf8cf55974/f058b/my-neighbor-cats-arch-v1.1.png 630w,
/static/787363958f7208cc6ea43bbf8cf55974/40601/my-neighbor-cats-arch-v1.1.png 945w,
/static/787363958f7208cc6ea43bbf8cf55974/7bf07/my-neighbor-cats-arch-v1.1.png 1128w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;&apos;우리 동네 고양이&apos; 프로젝트 구조 - 초기 설계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;발표 모임에서는 여러 가지 제안들도 나왔다. 기본 설계에서 더 보완할 점들(S3 bucket에 이미지 파일을 업로드할 때 API Gateway 거치지 않고 직접 올리는 게 낫다는 것 등)과 함께, 이 서비스가 제대로 만들어진다면 추가될 수 있을 각종 고급 기능들에 대한 아이디어들도 쏟아져 나왔다. 오, 이런 호의적인 반응이라니. 일단 아이디어로는 어그로를 끄는 데 성공한 것 같군. 미키는 안심이 되었다. AWS 솔루션 아키텍트(SA) 분들도 많은 조언을 해주었는데, 특히 S님이 ‘우리 동네 고양이’ 라는 이름이 좋다고 해줘서 고마운 마음이 들었다. 미키가 은근히 신경쓰는 것 중 하나가 이름 짓는 것이었거든. 알아본 사람이 있는지 모르겠지만 프로젝트의 영어 이름 ‘My Neighbor Cats’ 도 미키가 좋아하는 ‘이웃집 토토로’의 영어 제목, ‘My Neighbor Totoro’ 에서 따온 것이었다.&lt;/p&gt;
&lt;p&gt;그렇게 나름 관심을 받으며 시작한 프로젝트였다. 이제 그 기대에 부응하여 멋진 결과를 보여줘야 할 텐데, 날짜는 하루하루 가고 있고, 아직 제대로 시작은 못하고 있었다. 핑계가 있기는 했다. 이 프로젝트를 비롯하여 여러 참여 팀들의 AWS 계정을 인프라 팀에서 통합 관리해주기로 하였는데 아직 계정이 안 나오고 있었으니. 그래도 그와 상관없이 작업할 수 있는 것들은 미리 해놓아야 하는데…&lt;/p&gt;
&lt;p&gt;작업 영역은 자연스럽게 나뉜 상황이었다. 프론트엔드 쪽은 미키가, 백엔드 쪽은 W와 K가 나눠서 맡게 되었고, 아무래도 아이디어 제안자인 미키가 주도적으로 전반적인 진행을 끌고 가게 될 것이었다. 약간 불안 요소가 있다면 미키가 AWS에 대해서 그렇게 썩 잘 알고 있지는 못하다는 것이었다. 물론 앞선 몇 개월간 매주 열심히 세미나에 참여하기는 했다. 가끔씩 졸다가도 곧잘 질문도 하고, 실습 시간에도 가이드 따라서 AWS 콘솔 들어가서 클릭, 클릭 열심히 인프라 구성도 해보고 코드 copy &amp;#x26; paste 도 하고 그랬다. 하지만 실습 문서 따라해보는 거랑 직접 만들어보는 거랑은 많이 다를 거라는 건 미키도 이미 예상하고 있었다. 아마도, 거의 확실히, 수많은 삽질을 거쳐야 할 터였다. 그리고 그 삽질은 시작하자마자 시작된 셈이었다.&lt;/p&gt;
&lt;p&gt;어쩌면 그 삽질은 미키가 자초한 면이 있었다. 백엔드 Lambda 함수에서 사용할 언어는 W, K와 논의해서 파이썬으로 일단 정하였는데, 프론트엔드 기술 세트는 미키 맘대로 정하면 될 상황이었다. 미키는 여기저기 대충 둘러보다가 Next.js와 TypeScript를 쓰기로 했는데, 둘 다 미키로서는 거의 처음 다뤄보는 기술들이었다.&lt;/p&gt;
&lt;p&gt;“뭐, 어차피 배우자고 하는 실습 프로젝트이니까…”&lt;/p&gt;
&lt;p&gt;주어진 시간이 많은 편은 아니라서 약간 모험이기는 했다. 익숙한 언어로 한다 해도 예상치 못한 문제들이 튀어나올 텐데, 낯선 기술을 써보겠다고? 하지만 이럴 때 아니면 언제 또 접해보겠나 싶은 생각이 들었다. 혹여 완성을 못한다거나 실패하더라도 큰 위험 부담은 없는 데모 프로젝트이니까. 물론 W와 K에게 미안하고, 다른 사람들 보기에 창피하겠지만. 한편, 그동안 세미나와 이 실습 프로젝트 전체를 관리하던 AWS의 I 님이 당부한 한 마디가 응원의 메시지가 되었다.&lt;/p&gt;
&lt;p&gt;“개발자분들, 뭐 만들라고 하면 하나하나 다 이해한 다음에 하고 싶어하고 그러시는데요.&lt;br&gt;
다 필요 없고요. 아무 거나 갖다 쓰고, 일단 돌아가도록 만들어놓고 생각하세요.”&lt;/p&gt;
&lt;p&gt;미키는 고개를 끄덕였다. 그래, 일단 돌아가는 게 중요하지. 오늘도 지구는 돌고 있고, 세상은 넓고 카피할 코드도 많..을 것이다. 제발 그래야 할 텐데.&lt;/p&gt;
&lt;p&gt;일차 목표는 Next.js의 기본 샘플 앱에 페이지 하나를 추가하고 그 페이지에 들어가면 지도가 나오게 하는 것. 지도 API는 카카오 것을 쓰기로 바꾸었다. 그냥 느낌으로는 네이버 지도가 더 일반적일 것 같아서 처음 설계에 포함시켰는데, 은근히 덜컹덜컹, 걸리는 것들이 있었다. 이것도 미키의 느낌일 뿐일 수도 있는데, 네이버 클라우드 플랫폼 가입 계정이 있어야만 지도 API를 쓸 수 있다든지 하는 것도 약간 불편했고, 예제 코드들도 뭔가 입맛에 딱 맞는 것이 쉽게 얻어걸리지 않는 느낌이었다. 카카오 지도 API는 기본 계정만 있으면 사용할 수 있고, 문서와 예제도 조금 더 깔끔하게 정리된 느낌이 들었다. 그래, 이걸로 하자. 동네 지도에 마커 표시만 할 수 있으면 아무 지도나 상관은 없었다.&lt;/p&gt;
&lt;p&gt;코로나19 때문에 집에서 재택근무 중이던 미키는 오후 작업 시간이 거의 끝나서야 겨우겨우 API 대강 엮어서 지도 한 장을 띄울 수 있었다. Next.js 에 들어가 있는 server-side rendering 개념이 아직 좀 낯설기도 했고, TypeScript 코드에서 타입을 명시적으로 지정해주어야 하는 것을 빠뜨려서 자잘한 에러를 만나느라 삽질을 꽤 했다. JavaScript에서 타입 신경 안 쓰고 작업하는 것에 익숙해져서인지, 다시 타입을 꼭꼭 넣어주어야 하는 게 약간은 귀찮기도 했다. 얼핏 보니 ‘any’ 로 지정하면 대충 넘어가는 것 같기에, 미키는 일단 타입은 대강 생략하고 넘겼다. 약간 미안스런 마음이 들었지만 제대로 코드 정리하는 건 차차 해나가면 될 일이었다. I 님의 메시지를 다시 떠올리며 위안을 삼았다. “다 필요 없고요…”&lt;/p&gt;
&lt;p&gt;API key 같은 것은 코드에 포함되면 안 되니까 .env.local 파일에 넣어놓고, 커밋을 만들어서 PR을 올렸다. 정리도 안 된 코드로 된, 사실상 남의 예제 베낀 수준의 썰렁한 페이지 한 장 넣어놓은 것이지만 작업의 시작을 알릴 필요가 있었다. 이제 여기서부터 덧붙이고 부수고 고치면서 만들어가면 될 것이었다. 뭐가 돼도 되겠지, 미키는 중얼거리며 맥북을 닫았다. 일단 오늘은 여기까지 하자.&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;&lt;em&gt;(이어지는 글: &lt;a href=&quot;../my-neighbor-cats-part2/&quot;&gt;우리 동네 고양이 - part 2&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hnc-jihoon/my-neighbor-cats/pull/1&quot;&gt;PR #1: Init next.js for frontend and add Kakao map sample&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;이 글은 아직 공사중인 다른 블로그 사이트에 먼저 쓴 글입니다. 그 사이트가 공개되면 출처를 남기겠습니다.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[나의 얼렁뚱땅 오픈소스 참여기 - part 2]]></title><description><![CDATA[(이전 글: 나의 얼렁뚱땅 오픈소스 참여기 - part…]]></description><link>https://jihoon-ernesto.github.io/my-first-open-source-part2/</link><guid isPermaLink="false">https://jihoon-ernesto.github.io/my-first-open-source-part2/</guid><pubDate>Thu, 07 Oct 2021 09:37:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;(이전 글: &lt;a href=&quot;../my-first-open-source-part1/&quot;&gt;나의 얼렁뚱땅 오픈소스 참여기 - part 1&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;사실 이럴 생각까지는 아니었다. 이게 뭐 대단한 얘기라고 글을 두 편이나 나눠 쓰나? 일필휘지로 한달음에 갈겨 쓸 생각이었다. 그런데, 쓰다 보니 흐름상 이쯤에서 한번 끊어줘야겠다는 느낌이 들었다. 실제로도 xterm.js 에 PR 올린 후에 시간적인 단절이 있기도 했고.&lt;/p&gt;
&lt;p&gt;이슈와 PR을 등록한 다음은 기다림의 시간이었다. 내 맘 같아서야 금방이라도 누가 보고 “오케이, 잘 했어!” 하고 승인해주면 좋겠지만, 여긴 황야의 오픈소스 월드. 길 떠난 프로젝트 주인이 언제 돌아와 내 작은 메모 쪽지를 보아줄지 모르는 상황이었다. 앞서 등록된 다른 이슈와 PR들도 쌓여있는 것들이 많았다. “뭐야, 누가 이런 하찮은 걸 올렸어!” 하는 신경질적인 대답과 함께 빠꾸(?)를 먹을지도 모를 일이었다. 더 나쁜 건, 아무도 관심 주지 않아서 그냥 시간이 지나면서 묻혀버리는 것이었다. 내 github 계정의 프로파일 이미지라도 좀 그럴듯한 걸로 올려놓을 걸 그랬나. ‘사진도 없는 웬 듣보잡이 이상한 걸 올리고 그래..?’ 하고서는 휙 지나쳐버리면 어떡하나.&lt;/p&gt;
&lt;p&gt;그러던 어느 날.&lt;/p&gt;
&lt;p&gt;일주일 정도 지났을까. 아니, 열흘 정도였을까. 낯선 이메일이 날아왔다. 깃헙 불라불라 뭐라고 써있는데, 평소에 가끔 날아오던 스팸 메일과 좀 다른 모양의 스팸이었다. 앗, 그거다! 누가 내 거에다가 댓글을 달았나보다!&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/1d82d1bd41761cc2d36e1328c4cea057/28e7f/xterm-issue-comment-by-T.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 12.025316455696203%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAYElEQVR42m3FSw6CQBBAQe5/HKI3wpgo3Q3jfLGHZ5w1i0pN8+3O8njyFuO16rDqRiqNOBykelDatVQqYjtbiOTamHLOlFpRM1QNEUPU2ENAPw2NTshOP89L3jtf9/HfD0dcmks1g+bsAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;xterm-issue-comment&quot; title=&quot;&quot; src=&quot;/static/1d82d1bd41761cc2d36e1328c4cea057/f058b/xterm-issue-comment-by-T.png&quot; srcset=&quot;/static/1d82d1bd41761cc2d36e1328c4cea057/c26ae/xterm-issue-comment-by-T.png 158w,
/static/1d82d1bd41761cc2d36e1328c4cea057/6bdcf/xterm-issue-comment-by-T.png 315w,
/static/1d82d1bd41761cc2d36e1328c4cea057/f058b/xterm-issue-comment-by-T.png 630w,
/static/1d82d1bd41761cc2d36e1328c4cea057/40601/xterm-issue-comment-by-T.png 945w,
/static/1d82d1bd41761cc2d36e1328c4cea057/78612/xterm-issue-comment-by-T.png 1260w,
/static/1d82d1bd41761cc2d36e1328c4cea057/28e7f/xterm-issue-comment-by-T.png 1848w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption class=&quot;left&quot;&gt;(나의 해석: &quot;여기 말고 xterm을 갖다 쓰는 데서 구현하도록 하자꾸나.&quot;)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;T로 시작하는 아이디를 쓰는 사람이었다. 이 사람이 PR 쪽에도 코멘트를 달았나보다. 가보자.&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/ae157ea86d841b9023796c147f8714c8/b6e50/xterm-pr-comment-by-T.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 19.62025316455696%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAYAAACOXx+WAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAwElEQVR42mWO226DMBBE+f9Pan6lXBpDaLCN14SSxJecCtM+VH0YndFodzTV2+nEZfxElhXxN/yycvvaCDETUj74q/Sfj2csv8u6sT0C1bkfEL8waYM2luukC2cn2NnhxDO7g+4n01pjZ4uxM8Y6rpMp9zElKoDtvvHeNDRtS920dN1H8bva4ruS1V1Po0bq3lIrjVIDfT9wVorLOBJjPApDCIj3iBdkXyIH/3i/4Jwh3IX4gphe5JxJKRXtZTu/AUPQMAQN8SrLAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;xterm-pr-comment&quot; title=&quot;&quot; src=&quot;/static/ae157ea86d841b9023796c147f8714c8/f058b/xterm-pr-comment-by-T.png&quot; srcset=&quot;/static/ae157ea86d841b9023796c147f8714c8/c26ae/xterm-pr-comment-by-T.png 158w,
/static/ae157ea86d841b9023796c147f8714c8/6bdcf/xterm-pr-comment-by-T.png 315w,
/static/ae157ea86d841b9023796c147f8714c8/f058b/xterm-pr-comment-by-T.png 630w,
/static/ae157ea86d841b9023796c147f8714c8/40601/xterm-pr-comment-by-T.png 945w,
/static/ae157ea86d841b9023796c147f8714c8/78612/xterm-pr-comment-by-T.png 1260w,
/static/ae157ea86d841b9023796c147f8714c8/b6e50/xterm-pr-comment-by-T.png 1862w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption class=&quot;left&quot;&gt;
    (나의 해석: &quot;있잖아, 이 단축키를 쓰는 데는 macOS 터미널밖에 없어.&lt;br&gt;
    그러니까 이 키가 필요하다면 VS Code 쪽에서 커스텀 키로 넣는 게 좋겠어.&lt;br&gt;
    우리는 xterm을 가능한 한 작게, 논란거리 없도록 만들고 싶거든.&lt;br&gt;
    내가 VS Code 쪽에 이슈를 만들어놨으니, 네가 거기서 해결해보렴. 아니면 주말에 내가 할 거란다. ㅋ&quot;)
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;황야의 xterm 프로젝트의 주인이 돌아온 것이었다! 하지만 일단은 거절. 쳇, 그냥 넣어 주지. 여기에 이게 들어가면 다른 여러 응용 프로젝트들에서는 신경 안 써도 되는 일인데… 하지만 코어 쪽은 최대한 가볍게 유지하고 싶다는 T의 의견도 이해는 갔다. 좋아, 그럼 다시 VS Code 쪽으로 가보자.&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/65372a095439409f5ae43f36ae20bb84/277c6/vscode-issue-by-T.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 46.835443037974684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABeklEQVR42l2R7W7bIBiFc/8XtF/dn/UKtk6rorSLtG52HDxswHxjP5NpnKQ70gMI9B4OvLvD4YWHh8+07Ymmbevcnk503ZlxVFjnkHJASknf9/yVEiEEQvQopRmVZlkWNu2OxyPfnp6YrMV5fyHgQ6TMM/OyfGAtTjnXs03LZX9ld3h55XwWTC4yaIeefDXLZSblUonpRkgFM7m6btsWpfXVtCZcB+ccTW8Y3IzLC2leSOVCXj4k2ArXtEqNeB+4VzUMKdP0mt+dohGGTnrOg6fXkXFK9TzE/D6njA+JskDXvrHfP/Pl+ZF98/1mmHMm+IDRHjWuOJR29fYQU016ry2l6AQ/9298+vHI1+5/wxCZpsgwevreMCqL1h45OqwrpDTXf920PjnGxHzXnKvh2jXnPEZF1LASMMZjTWQyCe8KIbw36BYTTkrwa2xoreCP6ZB+vCQshRAjMWasz5jJM9mAtQE9BVwolDJXrs0BpFZ0Q49NDpc9oUT+ARZEuQimNPgMAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;vscode-issue&quot; title=&quot;&quot; src=&quot;/static/65372a095439409f5ae43f36ae20bb84/f058b/vscode-issue-by-T.png&quot; srcset=&quot;/static/65372a095439409f5ae43f36ae20bb84/c26ae/vscode-issue-by-T.png 158w,
/static/65372a095439409f5ae43f36ae20bb84/6bdcf/vscode-issue-by-T.png 315w,
/static/65372a095439409f5ae43f36ae20bb84/f058b/vscode-issue-by-T.png 630w,
/static/65372a095439409f5ae43f36ae20bb84/40601/vscode-issue-by-T.png 945w,
/static/65372a095439409f5ae43f36ae20bb84/78612/vscode-issue-by-T.png 1260w,
/static/65372a095439409f5ae43f36ae20bb84/277c6/vscode-issue-by-T.png 2522w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;VS Code 쪽에 T가 생성한 이슈&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;오잉, 설명은 그냥  링크로 때우고 코드 일부를 갖다 붙여놓았네? 오호, 이 부분을 고치면 된다는 뜻인가보군! 가만있자… 그 아래에 또 다른 사람 K가 댓글을 달았네.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;K: 이봐, 이거 지금 작업중이니? 아니라면 내가 가져갈게.&lt;br&gt;
T: jihoon-ernesto(= 나)가 해결할지도 모르니 며칠 기다려보는 게 어떻겠니?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;음, 이런 만만한 이슈에는 먹잇감을 노리는 하이에나들이 달려드는구나. 내가 얼른 처리해야겠어. 마침 T가 어떤 파일에 있는 어떤 코드를 고치면 되는지까지 알려줬으니 땡큐다. 먼저 xterm 쪽 PR에 대한 T의 코멘트에 대해 답을 해줘야겠다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;나: 알려줘서 고마워. 그렇다면 내가 거기에다가 PR을 만들게.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;부랴부랴 작업을 시작했다. 머뭇거리는 사이에 하이에나 K에게 내 업적(?)을 빼앗기면 안 될 일이었다.&lt;/p&gt;
&lt;p&gt;T가 알려준 좌표는 &lt;code class=&quot;language-text&quot;&gt;terminal.contribution.ts&lt;/code&gt; 파일. 여기에다가 뭔가 해야 하는 것이었군. 처음에 VS Code 들여다볼 때에는 딴 데만 기웃거리고 있었으니 삽질만 한 것이었다. 그 파일에는 ctrl-A, ctrl-E 등의 키에 해당하는 별도의 키를 추가로 등록하는 코드가 들어 있었고, 나도 비슷한 형식으로 집어넣으면 될 것 같았다. 전반적인 흐름이나 모듈 구성 등을 이해하지는 못했지만, 뭐 내가 하려는 일은 아주 작고 명확한 것이니까, 이것만 제대로 동작하면 될 것이었다. 어찌어찌 또 약간의 삽질 끝에 Code-OSS 실행하여 내장 터미널 창에서 커맨드 쩜의 동작을 확인할 수 있었다. 휴~&lt;/p&gt;
&lt;p&gt;문득, 혹시 PR을 올릴 때 unit test 코드도 항상 같이 포함시켜야 하나, 싶었다. 좀 귀찮기도 해서 안 하고 싶은 생각이 들었는데… 다행이군 ㅋ. 다른 사람들의 PR들을 보니 그냥 올린 것들도 많았다. 꼭 해야 하는 건 아니구나.&lt;/p&gt;
&lt;p&gt;자, 이제 다시 VS Code에 PR을 올리자. VS Code를 내 계정으로 fork 하고, 그걸 origin 삼아서 local 에 clone하고, &lt;code class=&quot;language-text&quot;&gt;cmd-dot-in-terminal&lt;/code&gt; 이라는 이름으로 작업 브랜치 만들고, 코드 수정하여 커밋을 만들었다. 이걸 &lt;code class=&quot;language-text&quot;&gt;git push&lt;/code&gt; 하고, github 웹페이지에 가서 PR 생성하였다. from 브랜치는 &lt;code class=&quot;language-text&quot;&gt;jihoon-ernesto:cmd-dot-in-terminal&lt;/code&gt; 이고, to 브랜치는 &lt;code class=&quot;language-text&quot;&gt;microsoft:main&lt;/code&gt; 이다. PR 제목은 T가 이슈 생성한 제목 그대로 썼다. 이 사람이 쓴 표현이 나보다 더 정확하겠지. 화살표 기호 하나만 살짝 바꾸었다.&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/6bd815bdb142cb1c3e6e37705a5dc853/37563/vscode-pr-by-me.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 26.58227848101266%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAABA0lEQVR42lWQXW6CQBSF2f8OTHw0LsIWrGLR+lZr3QFqEQRhZmCYGb6GSZrYk5yck3tzf4PD54HF4oW31YowjHj1DImWS9brmCTZstt9eL/ZvBNFS8Io4ut4JLvlpOmZvLhTVhWPuib4Pp2I45jtdizc/dNnnySJ9/v93vvzOWXEMAw8IzBdT9t2dFrjhgFjLNY6jHVenXP0xvr4M4y1aN1jncMYQ2+Mbx7ovKKpai4/N8+sKMmKiqoWCNnyaKSnVB1tp1Fth+q0zzdSIZViNpsxn8+x1hL8TavLB5dckOaSy11yLRryclRBemu4lgohFY0Q/ldaa7/peN1kMmE6nfpNfwFcFm9KKNK8DAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;vscode-pr&quot; title=&quot;&quot; src=&quot;/static/6bd815bdb142cb1c3e6e37705a5dc853/f058b/vscode-pr-by-me.png&quot; srcset=&quot;/static/6bd815bdb142cb1c3e6e37705a5dc853/c26ae/vscode-pr-by-me.png 158w,
/static/6bd815bdb142cb1c3e6e37705a5dc853/6bdcf/vscode-pr-by-me.png 315w,
/static/6bd815bdb142cb1c3e6e37705a5dc853/f058b/vscode-pr-by-me.png 630w,
/static/6bd815bdb142cb1c3e6e37705a5dc853/40601/vscode-pr-by-me.png 945w,
/static/6bd815bdb142cb1c3e6e37705a5dc853/78612/vscode-pr-by-me.png 1260w,
/static/6bd815bdb142cb1c3e6e37705a5dc853/37563/vscode-pr-by-me.png 2228w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;VS Code 쪽에 올린 PR&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;휴, 벌써 시간이 이렇게 되었잖아? 별로 큰 일 한 것도 아닌데 새벽이 되었네.&lt;/p&gt;
&lt;p&gt;다음 날.&lt;br&gt;
밤에 올린 PR에 댓글이 달려 있었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;T: 괜찮네. 땡스.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그리고는 T가 그 PR을 머지했다는 로그가 찍혀 있었다. 엥? 😳&lt;br&gt;
T는 xterm의 프로젝트 주인 아니었어? VS Code에 커밋 권한까지 있는 사람이었어??&lt;/p&gt;
&lt;p&gt;여기서 잠시 생각해보면, 내 커밋이 머지되기까지는 운이 좋았다. T가 손수 이슈를 등록해주면서 어느 위치를 고치면 되는지까지 알려주었고, xterm의 주인인 줄로만 알았던 이 사람이 알고 보니 VS Code 프로젝트의 커미터였으니. 그렇게 해서 엉겁결에 올린 PR이 VS Code의 메인 브랜치에 들어가게 되었다.&lt;/p&gt;
&lt;p&gt;그리고 다시 기다림의 시간.&lt;/p&gt;
&lt;p&gt;메인 브랜치의 코드는 적당한 때가 되어야 실제 제품에 포함되는 법. 드디어 1.60 버전에 이 커밋이 반영되었다.&lt;/p&gt;
&lt;figure style=&quot;max-width:848px&quot;&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/2b671fd33244afdbbdf50eb7cb738cb7/08c33/vscode-release-note-1.60.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 87.9746835443038%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAABYlAAAWJQFJUiTwAAACxklEQVR42nWU647iRhCF5/1faf/lDfJnpUSJdgYWfGn3/WK3sf1F1cAMWmVbKgrKcPpUnVO81VoxxmKdJ4VEGTRrXdmBfd/Zt+2e/ye2FkeL53k7jh2XK0OojLEypbW978OKDRk9TUxa45zDWou1BmM0Wht6m7j6ii0rx/EE3DdGX/hryPyjMh+6YPKKTisxZbwzeO8IweO8x/qAcR4fE6lu+PnGC0He5OU4DnLOOLlda1IMBGuIMaJ9xPhEypmYErHuuGWnbi8oL+ft2Hd8qVxM4d+r5jRYfvSWH53hdO0594qfvcJYh3cO5yzOWoz1TGFh9DPr7ca2bQ+Gx0HIC1eb6XylCyt9vOHmrbEO3hFDIKXYGHvvG6iMwYWAC/daSukL0ITMe6d5V4nzFFHaEr1rXzTGYK1D2+fsMrbcCPPtU4g2tteWTVo4ucoQV1Rc6VxhmGwTIXiPTxmTKjrVu2UO2I/fzFCuycvKVQfOg+ajU1yU5b2bcF7aDARp+dGutC2KSy0Gjw6ZMd7Qef1SWfiWnDB6YlIjk1JoNTbFlZoYx5FpmlBKMQxD+yxZav0wMIgfTSKV+QEI+DTzMViu033AKWXmeW7CSJRSWl0YNrHEh7ncn73Eg+HRfmDEDua+CZK1/soSwqiJ5DwqVlRaqbf9Fx8eO3FeOU+psTuPlo/eNIbCRlgJC8kyN7m4lEyca7NWXLZfROGumAAo2dtpQgtLaxsr+2AtOyx7bT/rDuUiP01poMuD6efqye3DMNJ3HeM40HVdCxGg7zsuo+Z9sFwm31hmCZn1XNs+57q9qiy7nFBqZBjVJ9PG9jE7awyjjVz82jbqd6cBxuuf9H//0WL4/o1x6BuoWENCWhULyZYI6ORiIyDeFJ86H0j19hQFjO45XU5Y0+FtT14qdVlaa0+bNAuVwjyXVrdpwZeV5ba1Dp//h/8BqUxpOCQNYnYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;vscode-release-note&quot; title=&quot;&quot; src=&quot;/static/2b671fd33244afdbbdf50eb7cb738cb7/f058b/vscode-release-note-1.60.png&quot; srcset=&quot;/static/2b671fd33244afdbbdf50eb7cb738cb7/c26ae/vscode-release-note-1.60.png 158w,
/static/2b671fd33244afdbbdf50eb7cb738cb7/6bdcf/vscode-release-note-1.60.png 315w,
/static/2b671fd33244afdbbdf50eb7cb738cb7/f058b/vscode-release-note-1.60.png 630w,
/static/2b671fd33244afdbbdf50eb7cb738cb7/40601/vscode-release-note-1.60.png 945w,
/static/2b671fd33244afdbbdf50eb7cb738cb7/78612/vscode-release-note-1.60.png 1260w,
/static/2b671fd33244afdbbdf50eb7cb738cb7/08c33/vscode-release-note-1.60.png 1570w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;VS Code 1.60의 release note 중에서&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;얘들아, 이거 봐! VS Code의 공식 릴리스 노트에 내 아이디가 들어갔어! 이제 우리가 한여름 땡볕 아래에서 에어컨을 켤 때마다 발명자 캐리어 님을 찬양하는 것처럼, VS Code 내장 터미널에서 커맨드 쩜을 누를 때마다 온 세상이 내 이름을 기억하게 될 거야. &lt;em&gt;영원히! Para siempre! Until the end of time! &lt;del&gt;(아님)&lt;/del&gt;&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
여기 대충 Mad Max ‘날 기억해 줘!’ 짤
&lt;br&gt;
&lt;br&gt;
(저작권 관계로 생략 ㅋ)
&lt;/blockquote&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
여기까지다. 어느 작고 귀여운 오픈소스 기여에 대한 장황한 이야기는. 또 모르지. 언젠가 다른 구석에서 누군가의 다른 이야기가 또 생겨날른지.
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;&lt;em&gt;The End&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xtermjs/xterm.js/issues/3400&quot;&gt;xterm.js issue #3400 - Need to handle ‘cmd + .’ on macOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xtermjs/xterm.js/pull/3401&quot;&gt;xterm.js PR #3401 - Handle ‘cmd + .’ on macOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/vscode/issues/130990&quot;&gt;VS Code issue #130990 - Add terminal keybinding for cmd+. -&gt; ctrl+c to match Terminal.app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/vscode/pull/131025&quot;&gt;VS Code PR #131025 - Add terminal keybinding for cmd+. → ctrl+c to match macOS Terminal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/updates/v1_60&quot;&gt;VS Code v1.60 Release Note&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=%EB%A7%A4%EB%93%9C%EB%A7%A5%EC%8A%A4+%EA%B8%B0%EC%96%B5%ED%95%B4+%EC%A4%98&quot;&gt;Google search: “매드맥스 기억해 줘”&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;이 글은 아직 공사중인 다른 블로그 사이트에 먼저 쓴 글입니다. 그 사이트가 공개되면 출처를 남기겠습니다.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[나의 얼렁뚱땅 오픈소스 참여기 - part 1]]></title><description><![CDATA[세 줄 요약 VS Code에 내가 원하는 단축키가 없길래, xterm.js에 코드 한 줄 넣으려다가 결국 VS Code…]]></description><link>https://jihoon-ernesto.github.io/my-first-open-source-part1/</link><guid isPermaLink="false">https://jihoon-ernesto.github.io/my-first-open-source-part1/</guid><pubDate>Mon, 27 Sep 2021 02:53:00 GMT</pubDate><content:encoded>&lt;h3&gt;세 줄 요약&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;VS Code에 내가 원하는 단축키가 없길래,&lt;/li&gt;
&lt;li&gt;xterm.js에 코드 한 줄 넣으려다가&lt;/li&gt;
&lt;li&gt;결국 VS Code에 들어가게 되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;긴 이야기&lt;/h3&gt;
&lt;p&gt;자, 그럼 시작해보자. 이 이야기는 장황해질 수도 있다. 그래도 내용은 별 거 없고 사실 위에 적은 게 다다. 하지만 우리는 뭐하러 블로그에 글을 적고 그걸 또 읽고 앉았는가. 그냥 단지 뭐라도 구구절절 이야기를 쓰고 싶고, 읽고 싶을 뿐이지 않은가.&lt;/p&gt;
&lt;p&gt;어느 개발자분이 그런 얘길 했다. 인터넷에 돌아다니는 수많은 정보들은 대부분 초보를 막 벗어난 사람이 초보에게 알려주는 기초적인 내용들이 많다고. 이 글 또한 그러하다. 오픈소스에 대해 잘 모르던 어떤 사람이 어쩌다 보니 코드 한 줄을 오픈소스 프로젝트에 넣게 된 이야기이다. 별 거 아니라면 별 거 아니지만, 그래도 또 누구한테는 티끌만큼이라도 도움이 될지도 모른다. 아니, 뭘 또 도움 씩이나. 그런 거 아니어도 상관 없다. 어쨌든 시시한 이야기거리 하나는 남게 될 테니 말이다.&lt;/p&gt;
&lt;p&gt;때는 바야흐로 2021년, 지구상의 가장 대표적인 소스 코드 저장 공간 GitHub이 MS의 후원을 등에 업고 맹위를 떨치고 있고, 컴퓨터 좀 만진다는 사람들은 누구나 거기에 저장소 만들어서 이런저런 SW 프로젝트를 만들고 참여하는 시절이다. 얼굴도 이름도 모르는 사람들끼리 힘을 합쳐 좋은 걸 만들어보겠다고 지혜와 기술을 모으는 오픈소스 프로젝트! 멋지지 않은가.&lt;/p&gt;
&lt;p&gt;나도 그런 데 한 자리 끼어서 뭔가 그럴듯한 기여를 하면 좋을 것 같다는 생각은 한참 전부터 해왔다. 폼 나지 않겠나? 그런데 뭘 어디서부터 해야 하나. 세상에 오픈소스 프로젝트는 수천 개, 수만 개는 되니 어디를 기웃거려야 할지도 모르겠고, 유명한 프로그램의 소스를 받아보아도 뭘 어떻게 해야할지 잘 모르겠고…&lt;/p&gt;
&lt;p&gt;한편, 나도 여느 개발자들처럼 VS Code 에디터를 메인 작업 도구로 사용하고 있는 중이었다. 어느 새 대세로 자리잡은 이 프로그램에 딱히 불만은 없는데, 단 하나 아쉬운 점이 있었으니 그것은 바로 내장 터미널에서 내가 즐겨 쓰는 단축키 하나가 안 먹는 것이었다.&lt;/p&gt;
&lt;p&gt;macOS의 기본 터미널을 보자. 이걸 안 쓰고 iTerm이나 다른 걸 쓰는 사람들도 많은 것 같지만, 나로서는 OS의 기본 앱이 큰 문제 없으면 그걸 주로 쓰는 편이다. macOS 터미널도 아직까지는 불편함을 못 느끼고 잘 쓰고 있다.&lt;/p&gt;
&lt;p&gt;터미널을 쓸 때 곧잘 누르게 되는 단축키가 ctrl-C 이다. 아시다시피 뭔가 프로그램을 실행하다가 중단시키고 싶을 때 break 역할로 쓴다. 그런데 macOS에서 이 키를 쓰기는 좀 불편한데, 그건 Mac 키보드에서 control 키를 찾아서 누르기가 영 마땅치 않기 때문이다. 맥북의 키보드에서도 그렇고 요즘 나오는 아이맥에 딸려오는 무선 키보드에서도 control 키는 참 애매한 위치에 있다. 맨 왼쪽 아래 Fn 키 바로 옆에 한 자리 차지하고 있다.&lt;/p&gt;
&lt;figure style=&quot;max-width:500px&quot;&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/73c72f3fd1c747889fca4eeeb757ba31/a8e5b/mac-control-key.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 31.0126582278481%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABNElEQVR42lWR63KCMBCFef+HausF5RICEgLYotVKW6fcBBHU2jmdrK0z/jiTnd3k7H4bTQQhql2LQ3dGezjd1PXfsJmH9dsHvrIKls0RzxfIixqG6SCKExRlAxHEcPgMWV4jfd9CE0Jik36ibjo0+57Ouu7QtidYjGO1TtEfL/BFBF9IigMZk1RjVTctB1XV0luNux7GukFJfWJiatgwTQZdN/E0GGEyveZUPBpPYVkcD48DDEc6bOZSfTAcE4FhMmgikISh3JXpJt3+4bqEoCZSWArxePpBUdSEmCzXtKY7MjWhwnh+WaLrz9eLixXKqgFzPLyuNqh2e8hwTqZZXiHLS3DXR5Ks0PWXm+G/tLIs4Xo+ZBjTzrg7gwgiWLZDefVpDvfAHJdiJZtxqoXRHFLGd/oF1mSu2i2k6OsAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;mac-keyboard&quot; title=&quot;&quot; src=&quot;/static/73c72f3fd1c747889fca4eeeb757ba31/f058b/mac-control-key.png&quot; srcset=&quot;/static/73c72f3fd1c747889fca4eeeb757ba31/c26ae/mac-control-key.png 158w,
/static/73c72f3fd1c747889fca4eeeb757ba31/6bdcf/mac-control-key.png 315w,
/static/73c72f3fd1c747889fca4eeeb757ba31/f058b/mac-control-key.png 630w,
/static/73c72f3fd1c747889fca4eeeb757ba31/a8e5b/mac-control-key.png 711w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;자, 눈으로 안 보고 control 키 눌러보라. 할 수 있겠는가?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;난 아직 이걸 안 보고 제대로 눌러본 적이 없다. 그래도 별 불편은 없는 게, macOS에서 중요한 키는 command 키이기 때문에 사실 control 키는 별로 누를 일이 없기 때문이다. 딱 한 경우, 터미널에서 ctrl-C 를 누를 때 빼고는.&lt;/p&gt;
&lt;p&gt;그런데 마침맞게도 macOS 터미널에서는 더 나은 방법이 있었으니, 그것은 바로 cmd-. (커맨드 쩜) 을 누르는 것이었다. 이게 있는 걸 알고 아주 좋았다. 이제 더 이상 control 키 찾느라 두리번거리지 않아도 된다! 그리하여 불편 없는 터미널 생활을 하고 있던 차에, VS Code에 내장된 터미널을 써보니 아뿔싸, 여기에서는 그 키가 안 먹는 것이었다.&lt;/p&gt;
&lt;p&gt;여기서 잠깐, 왜 굳이 VS Code 내장 터미널을 쓰느냐고? macOS 기본 터미널이 좋다면서 그냥 그걸 쓰면 되지 않느냐고?&lt;/p&gt;
&lt;p&gt;좋은 질문이다. 나도 처음에는 그렇게 쓰곤 했는데, 다른 프로젝트 소스를 몇 개 열고 왔다갔다하면서 뭘 하다 보면 개발툴 안에 내장된 터미널을 쓰는 게 낫다는 생각이 든다. A 프로젝트 소스를 VS Code 창 하나에 띄워놓고, &lt;code class=&quot;language-text&quot;&gt;yarn dev&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;git switch&lt;/code&gt; 등의 명령어 실행을 위해서 별도의 터미널 창 하나를 띄우고 하다가, B 프로젝트 작업을 할 일이 생겨서 또 VS Code 창 하나를 띄우고 그것의 실행을 위해서 터미널 창 또는 탭을 하나 더 띄워서 하다 보면, 이 창 저 창, 이 앱 저 앱 왔다갔다하는 게 여간 귀찮은 게 아니다. 그러니 프로젝트별로는 VS Code 창 하나씩만 띄우고 터미널은 그 안에서 내장 터미널을 열고 작업을 하는 게 훨씬 낫다. 최소한 내게는 그렇다.&lt;/p&gt;
&lt;p&gt;결국 그렇게 문제가 불거진 것이다. VS Code, 다른 건 다 좋은데 내장 터미널에서 ‘커맨드 쩜’ 단축키가 안 먹는다는 것.
다른 사람들에게 물어보기도 했다. ‘그런 단축키가 있었어요?’ 하는 반응이 돌아왔다. 음, 아주 인기있는 키는 아닌가보군. ‘구글신에게 한번 물어보세요’&lt;/p&gt;
&lt;p&gt;하지만 신은 내게 쉽사리 응답해주지 않았고, 나는 아쉬움을 참고 그냥저냥 불편하게 지내고 있었다. 가끔 두리번거리며 control, c, 를 눌러가면서.&lt;/p&gt;
&lt;p&gt;그러던 어느 날.&lt;/p&gt;
&lt;p&gt;주말이 시작되는 금요일 저녁이었나보다. 아니, 토요일이었던가? 잘 모르겠다. 어쨌든 그날 나는 무료함을 느끼고 있었고, 마침 별로 할 일이 없었다. 사실 정말 할 일이 없던 건 아니었다. ‘성질 나는데 그 문제나 한번 풀어볼까?’ 하는 생각이 들었다. 물론 진짜 성질이 난 건 아니었다.&lt;/p&gt;
&lt;p&gt;VS Code의 github 페이지를 찾아갔다. &lt;code class=&quot;language-text&quot;&gt;git clone&lt;/code&gt;을 하고, 빌드를 해봤다. 음, 시키는 대로 하니까 실행이 되는군. 정식 배포되는 버전이랑 헷갈리지 않도록 다른 아이콘으로 표시되면서 Code-OSS 라는 이름으로 실행이 되었다. 좋아, 어디를 고치면 되는지 찾아보자. 흠, Electron 기반이고 TypeScript가 주로 쓰이고 있군. 문제가 될 만한 부분은… 잘 모르겠군.&lt;/p&gt;
&lt;p&gt;얼마간의 삽질 끝에 얻은 소득은, VS Code에 내장된 터미널은 xterm.js 라는 라이브러리를 가져다 썼다는 걸 알아낸 것이었다. Blazing banana (feat. 치코 봉봉) 하나 먹으면서 곰곰 생각해보니, xterm에서 커맨드 쩜 단축키를 지원한다면 VS Code에서는 자연스럽게 지원될 수 있을 것이었다. 그래, 그게 낫겠어.&lt;/p&gt;
&lt;p&gt;xterm.js의 github 페이지를 찾아갔다. &lt;code class=&quot;language-text&quot;&gt;git clone&lt;/code&gt;을 하고 빌드를 해봤다. 음, 시키는 대로 하니까 실행이 되는군. 뭐야, 여기도 TypeScript가 쓰이고 있군. 요즘은 다 이걸로 하나? 뭐 어쨌든 좋아. package.json 파일을 살펴보니 start 스크립트가 있군. 실행을 해보자. localhost 3000 포트로 뭔가가 실행되는군. 브라우저로 접속을 해보니, 오호, 디버그용 데모 페이지가 잘 만들어져 있다. 고친 다음 여기서 확인해보면 되겠네. 좋아, 어디를 고치면 되는지 찾아보자.&lt;/p&gt;
&lt;p&gt;이거는 좀 알 것 같았다. Keyboard.ts 라는 소스 파일이 있는데 여기 보니 여러 가지 키들에 대한 동작 정의가 되어 있는 것 같았다. 내가 추가하려는 커맨드 쩜 단축키는 macOS 전용이니, isMac 조건값에 따라 동작하도록 하면 될 것이었고, 마침 비슷한 코드가 이미 들어 있었다. command-a 를 누르면 다른 OS의 ctrl-a 처럼 ‘전체 선택’이 되게 하는 코드가 보였다.&lt;/p&gt;
&lt;p&gt;이 조건문 안에 비슷하게 넣으면 될 것 같군. 가만있어보자, 쩜 키를 누를 때의 키 코드가 뭐였더라? 콘솔에 로그를 찍어보는 게 확실하겠군. 그런데, 코드 수정하고 실행했는데 왜 콘솔에 아무 것도 안 찍히는 거지? 아, 이거는 .ts 소스잖아, .js로 트랜스파일되었는지 확인해야지. 역시 안 되었군. &lt;code class=&quot;language-text&quot;&gt;yarn build&lt;/code&gt;를 하고 다시 돌려보자. 오케이, 나온다. 쩜을 누를 때의 키 코드는 190이군. 그럼 이제 그걸 콘트롤-씨로 매핑해야 하는데… 남들 해놓은 것을 보니 대충 result.key 값을 바꿔주는 것 같군. C0 라는 namespace에 값들이 선언되어 있는 것 같은데, 오 여기 있다. 콘트롤-씨에는 ETX라는 이름이 붙어있구나. 그걸로 키 값을 바꿔주고, 어디 한번. 오, 된다. 디버그용 데모 페이지에서 커맨드 쩜이 인식된다!&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/0e52b91a97115049c3edcc8c58a3071c/2ed34/xterm-demo-page.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 58.86075949367089%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABPElEQVR42tWTy2oCQRBF28ckIr414AtduvRHRHTjP2k6woASI36Xgog4M8gEIsxsskrghK5gkEiCCWSRgkt1V9W9dRfdik8RBgGO6+B5LofDAdd18TyPnbOTs+/7+P4jTy/w/MpZqCAImM1mzOdzwXQ6ZTweC2zbFoxGI4bDIVpr7rTmVmu0PWFyb3gPwl8sFoRhiNpsNtTrdRqNBpVKhWazSbVapVarUS6XpV4sFslkMqTTack3pRLXVxZKKSKRiOREIsF6vUY5jkO73abVapHL5YSUzWZJpVJCNigUCuTzeYGZMXczF41GicViIphMJt8Ft9utODMuDfl06yU4c7hcLj8ax+ap4LH+1ZJvBS919c8FV6uVFCzLIh6P/xiGZ0TNq/gbh+ZbdToder3er9Dv9+l2uwwGA/b7PW/ekZnHQd3iFwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;xterm-demo-page&quot; title=&quot;&quot; src=&quot;/static/0e52b91a97115049c3edcc8c58a3071c/f058b/xterm-demo-page.png&quot; srcset=&quot;/static/0e52b91a97115049c3edcc8c58a3071c/c26ae/xterm-demo-page.png 158w,
/static/0e52b91a97115049c3edcc8c58a3071c/6bdcf/xterm-demo-page.png 315w,
/static/0e52b91a97115049c3edcc8c58a3071c/f058b/xterm-demo-page.png 630w,
/static/0e52b91a97115049c3edcc8c58a3071c/40601/xterm-demo-page.png 945w,
/static/0e52b91a97115049c3edcc8c58a3071c/78612/xterm-demo-page.png 1260w,
/static/0e52b91a97115049c3edcc8c58a3071c/2ed34/xterm-demo-page.png 1776w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;xterm.js의 디버그용 데모 페이지 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;아, 일단 한 고비 넘은 것 같다. 잘 했으니 술 한 잔 하고 오자. (우유 마심)&lt;br&gt;
그럼 이제 어떡하지? 요거 고친 거를 바로 올리면 되나? 음, 아냐. 이거를 고쳤을 때 진짜로 VS Code에서도 키가 먹는지를 확인해야겠어.&lt;/p&gt;
&lt;p&gt;그런데, 내가 고친 xterm을 VS Code에서 쓰게 하려면 어떻게 하면 되지? 찾아보자, 찾아보자… 아, 이런 방법이 있군. xterm쪽에서 &lt;code class=&quot;language-text&quot;&gt;npm pack&lt;/code&gt;을 하고, .tar 파일을 옮겨다 적당한 데다 풀어서 package라는 폴더를 만들고, VS Code 쪽에서는 &lt;code class=&quot;language-text&quot;&gt;yarn add&lt;/code&gt;로 그 폴더를 설치. 오, package.json에서 xterm 항목이 내가 수제 가공한 버전으로 경로가 바뀌었네. 이렇게도 dependency가 연결될 수 있구나.&lt;/p&gt;
&lt;figure style=&quot;max-width:800px&quot;&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/d875efe7bcdd4efc8553824b0aaa2293/d0c2f/vscode-package-json.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 12.658227848101264%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAsklEQVR42k2H0WrCMAAA+yVNtXGWRW1cjdsYNtVWTToo7icESyZj+39uKB3s4bi7SG8qVtuG18M7y6eC0iypXlYopZhmGVKOSdMEKUdImdy5/WRwOv770b0jYw2+23L9+aa/BsLlzNdnTwgXQujpThvq5pGjy/Eup/Wa5jDHuRxbKco3RWVn+FZj7YzIuI7n9oOidqz9iaKsMQtFbTT7tWZncubZA7EQCBGTDI4HxD/f+AXOz2HofIj+iQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;vscode-package-json&quot; title=&quot;&quot; src=&quot;/static/d875efe7bcdd4efc8553824b0aaa2293/f058b/vscode-package-json.png&quot; srcset=&quot;/static/d875efe7bcdd4efc8553824b0aaa2293/c26ae/vscode-package-json.png 158w,
/static/d875efe7bcdd4efc8553824b0aaa2293/6bdcf/vscode-package-json.png 315w,
/static/d875efe7bcdd4efc8553824b0aaa2293/f058b/vscode-package-json.png 630w,
/static/d875efe7bcdd4efc8553824b0aaa2293/40601/vscode-package-json.png 945w,
/static/d875efe7bcdd4efc8553824b0aaa2293/78612/vscode-package-json.png 1260w,
/static/d875efe7bcdd4efc8553824b0aaa2293/d0c2f/vscode-package-json.png 1362w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;VS Code의 package.json에 local xterm 경로가 지정되었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;어디 그럼, 이제 요걸로 VS Code를 실행해보자. 빌드를 한 번 해주고, Code-OSS 실행하니… 오오, 된다! &lt;em&gt;(감동의 물결~)&lt;/em&gt;&lt;br&gt;
좋아, 그럼 이제 Pull Request 올려보자.&lt;/p&gt;
&lt;p&gt;회사 프로젝트 작업할 때 GitLab의 Merge Request 만드는 거랑 같겠지만, 그래도 혹시 몰라 xterm의 안내 페이지를 여러 번 참고해보았다. 내 딴에는 잘 한다고 수정해서 올려도, 그쪽 규칙에 안 맞는다거나 하면 안 되니까. Contributing 페이지에 뭐라고 써있나. 일단 이슈를 하나 등록하고(JIRA 이슈 같은 거겠지), 그것을 내가 고치겠다고 명시하고, 그 다음에 PR을 올리면 되는 것 같았다. 맞다, 설마 이 커맨드 쩜 단축키에 관한 이슈가 이미 올라와있거나 하진 않겠지? 기존 이슈들을 쭉 둘러본 결과 그렇지는 않았다. 좋다. 그럼 이슈를 등록하자. 커맨드 쩜 단축키가 왜 필요한지 나름대로 간단명료하게 쓰려고 노력했다.&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/0885abe0475fb467427773c7d35d251d/09262/xterm-issue.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 49.36708860759494%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABlklEQVR42nWSW2/UMBCF81KkXjbJ5uI4zsWX2Mkm2S5tlyKQUJ+qCgkkXpH4/7/jIE+WJaj04dPYM8fj8UmCxuxwePgEuztgt3/AePgA0+8J0VqY4ZZyHq9tzYgoE9jEDJtt8YqA8QrO9eg6C+t6wnQWxloobdBZB9cPaJWmRnEmEP6n0blh2RgUQmKblUhyQXFNlBaIkgV/IEw4orR8k+DXj5/49vwdXA4Y5iOkndF2M2o9oqg75MKcYZU55TQyLhdK9Q9BGDNESYlKOrTdiEYPqFVPKDuh1gN5J+20xG4kbcJqpEVD8Q/ejuBmyxDnAm66Qz/dYZjvYcf30M5/FAcmFMqmO2FRVHpZtxZCOlrzUz3jLYJ311tcRflZyGtzbsAbQ3tf85EgzaL1l/man/Ryk+ImZggej59xuz8i4S1NkAsFJjSJs1IiLdq/8BWrnNf5cwlrEHx9esGXj0+o9A79dA/lZlRqIPO9MPE+Fc3i14p0lctLRZP7fXBxFeMyTJH7W0pJk8V5hesof/Nfew2j54ZJgd9scwhK+ZWc1gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;xterm-issue&quot; title=&quot;&quot; src=&quot;/static/0885abe0475fb467427773c7d35d251d/f058b/xterm-issue.png&quot; srcset=&quot;/static/0885abe0475fb467427773c7d35d251d/c26ae/xterm-issue.png 158w,
/static/0885abe0475fb467427773c7d35d251d/6bdcf/xterm-issue.png 315w,
/static/0885abe0475fb467427773c7d35d251d/f058b/xterm-issue.png 630w,
/static/0885abe0475fb467427773c7d35d251d/40601/xterm-issue.png 945w,
/static/0885abe0475fb467427773c7d35d251d/78612/xterm-issue.png 1260w,
/static/0885abe0475fb467427773c7d35d251d/09262/xterm-issue.png 1896w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;xterm 프로젝트에 이슈 등록한 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;다음, xterm.js 소스를 내 계정 밑으로 fork 했다 (처음엔 이 개념이 굉장히 낯설었다). 이제 그걸 origin 삼아서 로컬에 clone하고, 코드를 수정하고 (두 줄짜리 if 문 추가), 로컬에 커밋하고, &lt;code class=&quot;language-text&quot;&gt;git push&lt;/code&gt; 실행. 그 다음 github 웹으로 가서 PR을 작성했다. 두근두근, 설렌다. 외부 세계에 내 목소리를 내는 것이다. “저기요, 제가 이런 거 한번 고쳐봤거든요. 어떻게 좀 한번 봐주시겠어요…?”&lt;/p&gt;
&lt;figure&gt;
  &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/9dc806700ed7da158a4d17ec3caf0773/0e0c4/xterm-pr.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 39.24050632911392%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAABRUlEQVR42nXRW0+DMBgGYG5M1AkbBQq0pS0rh8EOME8zMV7s1sT//3Ne085t6vTiSV/a9Cv96qmqx2q7Q9UNqPsRQjdQpkPTj1hvdzCLDaTpQJmGHyYISHoQ/uR/8ZhQMFUNqUqUc4NCKkilXdbl4dviokDOxAnjhWPnacbOBa/9CCQVSLkGoRyzKEdEBcKEIYwZ4ky6eUIFklw5NvshPf8tSXE3o4739rrHMO5AhQFXDSgrkfK5E2e2gD6xa5SXLhNa/Mn72L/jaXwBL1uYdgOuWzDVuDETBgkrQdLi7Lg5lReiTMK7msxwE0TgqkbTD+5xFqt7mHaNuhvAZIXbIMZkaiXuWq5fdnSZfsspvCnJEZDM9apaPqDbPGI5PKPQDZiqkRfGHWblsnL9OxX9xdbxjiFhGpFoMI0OB7hHSfiF4/p/PgE7/dB5wMsrRgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;xterm-pr&quot; title=&quot;&quot; src=&quot;/static/9dc806700ed7da158a4d17ec3caf0773/f058b/xterm-pr.png&quot; srcset=&quot;/static/9dc806700ed7da158a4d17ec3caf0773/c26ae/xterm-pr.png 158w,
/static/9dc806700ed7da158a4d17ec3caf0773/6bdcf/xterm-pr.png 315w,
/static/9dc806700ed7da158a4d17ec3caf0773/f058b/xterm-pr.png 630w,
/static/9dc806700ed7da158a4d17ec3caf0773/40601/xterm-pr.png 945w,
/static/9dc806700ed7da158a4d17ec3caf0773/78612/xterm-pr.png 1260w,
/static/9dc806700ed7da158a4d17ec3caf0773/0e0c4/xterm-pr.png 1884w&quot; sizes=&quot;(max-width: 630px) 100vw, 630px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
  &lt;figcaption&gt;xterm 프로젝트에 PR 올린 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;자, 이제 루비콘 강을 건넜고, 주사위는 던져졌다. 과연 이 PR은 어떤 처분을 받게 될 것인가.&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;&lt;em&gt;(이어지는 글: &lt;a href=&quot;../my-first-open-source-part2/&quot;&gt;나의 얼렁뚱땅 오픈소스 참여기 - part 2&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;VS Code
&lt;ul&gt;
&lt;li&gt;GitHub page: &lt;a href=&quot;https://github.com/microsoft/vscode&quot;&gt;https://github.com/microsoft/vscode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;xterm.js
&lt;ul&gt;
&lt;li&gt;GitHub page: &lt;a href=&quot;https://github.com/xtermjs/xterm.js&quot;&gt;https://github.com/xtermjs/xterm.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xtermjs/xterm.js/blob/master/CONTRIBUTING.md&quot;&gt;How to contribute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xtermjs/xterm.js/issues/3400&quot;&gt;issue #3400 - Need to handle ‘cmd + .’ on macOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xtermjs/xterm.js/pull/3401&quot;&gt;PR #3401 - Handle ‘cmd + .’ on macOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@johnyworld/NPM-package-%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8%ED%95%98%EA%B8%B0&quot;&gt;NPM package 로컬에서 테스트하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;이 글은 아직 공사중인 다른 블로그 사이트에 먼저 쓴 글입니다. 그 사이트가 공개되면 출처를 남기겠습니다.&lt;/em&gt;&lt;/p&gt;</content:encoded></item></channel></rss>