<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>용감한 남매들 Tech Blog</title>
    <description>치킨집 하지 말자.
</description>
    <link>https://bravenamme.github.io/</link>
    <atom:link href="https://bravenamme.github.io/rss" rel="self" type="application/rss+xml"/>
    <pubDate>Mon, 28 Mar 2022 10:08:48 +0900</pubDate>
    <lastBuildDate>Mon, 28 Mar 2022 10:08:48 +0900</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
      <item>
        <title>2.5D 구현하기 - 쿼터뷰</title>
        <description>&lt;h2 id=&quot;들어가며&quot;&gt;들어가며&lt;/h2&gt;
&lt;p&gt;여러번 2D 게임을 만들기도 하고 즐기기도 하면서 여러가지 게임 그래픽에 대한 테크닉에 대해서 공부를 해보았습니다. &lt;a href=&quot;/2020/12/09/raycasting-pseudo-3d/&quot;&gt;참고 - 울펜슈타인3D 는 과연 어떻게 3d를 구현했을까요?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;이번에는 그 중에서 쿼터뷰에 대해서 이야기를 해보고자 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://imagescdn.gettyimagesbank.com/500/19/592/773/0/1147490682.jpg&quot; alt=&quot;quarter view&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;등축-투영법&quot;&gt;등축 투영법&lt;/h2&gt;

&lt;p&gt;먼저 기본되는 원리를 알려면 &lt;strong&gt;등축 투영법&lt;/strong&gt; 을 알아야 합니다. &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%93%B1%EC%B6%95_%ED%88%AC%EC%98%81%EB%B2%95&quot;&gt;참조&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;원래는 제도 분야에서 많이 쓰이는 투영법 중 하나이지만, 게임 분야에서 복잡한 3D 계산을 하지 않고, 2D 그래픽만으로도 쉽게 표현할 수 있는 장점 때문에 많이 쓰이고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Perspective_isometrique_cube_gris.svg/330px-Perspective_isometrique_cube_gris.svg.png&quot; alt=&quot;등축 투영법&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;타일-기반-2d-게임&quot;&gt;타일 기반 2D 게임&lt;/h2&gt;

&lt;p&gt;보통 2D 게임을 만들때 2D 좌표 기반으로 미리 그려진 이미지를 타일처럼 
배치하는 형식으로 맵을 디자인하곤 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://assetstorev1-prd-cdn.unity3d.com/key-image/30beaf60-994f-490b-92fc-6e646716b869.png&quot; alt=&quot;2D Top down Game&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn5.vectorstock.com/i/1000x1000/40/14/2d-tiles-set-for-top-down-games-vector-27294014.jpg&quot; alt=&quot;2D tiles&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이번에 소개해드릴 쿼터뷰도 동일하게 타일처럼 맵을 디자인할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn1.epicgames.com/ue/product/Featured/2DIsometricTilesSet_featured-894x488-796ca84f8f5fba03b3419a34848860d2.png&quot; alt=&quot;Isometric tilemap&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다만 쿼터뷰는 일반적인 2차원 좌표계랑 다른데 어떻게 구성해야 할까요?&lt;/p&gt;

&lt;h2 id=&quot;cartesian-좌표계--isometric-좌표계&quot;&gt;Cartesian 좌표계 / Isometric 좌표계&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;일반적인 x/y 2차원 좌표계는 Cartesian 이라고 부릅니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;일반적인 2d 타일맵을 아까 이야기 했던 &lt;strong&gt;등축 투영법&lt;/strong&gt; 방식으로 표현한 것을 아까 이야기했던 쿼터뷰 혹은 isometric 이라고 부릅니다.&lt;/p&gt;

&lt;p&gt;아래 사진처럼 수직축으로 45도 회전시킨 다음, 이어서 수평 축으로 +/- 35.264° [= arcsin(tan(30°))] 회전시킨 것과 같습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.tutsplus.com/cdn-cgi/image/width=400/gamedev/uploads/2013/05/the_isometric_grid.jpg&quot; alt=&quot;Cartesian grid vs. isometric grid&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;그럼-어떻게-표현해야-할까요&quot;&gt;그럼 어떻게 표현해야 할까요?&lt;/h2&gt;

&lt;p&gt;아래 이 이미지는 32x32 사이즈의 투명한 배경을 가진 이미지입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20220327/iso-block.png&quot; alt=&quot;isometric block&quot; /&gt;&lt;/p&gt;

&lt;p&gt;쿼터뷰는 아래 사진을 이런식으로 배치하는 형식으로 시작됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20220327/iso-block-couple.png&quot; alt=&quot;isometric block couple&quot; /&gt;&lt;/p&gt;

&lt;p&gt;단순히 이렇게 쌓는 것으로 끝입니다.&lt;/p&gt;

&lt;p&gt;정리하자면 일반적인 2D 맵과 달리 isometric 은 아래와 같이 겹치는 구조로 되는 것 입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20220327/cartesian2isometric.png&quot; alt=&quot;cartesian to isometric&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그렇다면 어떤 규칙으로 배치될까요?&lt;/p&gt;

&lt;p&gt;식으로 표현하면&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isoX&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cartX&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cartY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isoY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cartX&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cartY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;isometric 의 x 좌표는 기존 좌표계에서 x - y 를 뺀 값이며
(게임내 구현은 첨부된 이미지의 너비만큼 곱해야 합니다.)
y 좌표는 기존 좌표의 x + y 를 더한 값을 나눠야 합니다.&lt;/p&gt;

&lt;h2 id=&quot;결과&quot;&gt;결과!&lt;/h2&gt;

&lt;div style=&quot;position: relative; height: 0; padding-bottom: 56.25%; padding-top: 25px;&quot;&gt;
&lt;iframe src=&quot;//labs.phaser.io/view-iframe.html?src=src/depth sorting/isometric blocks.js&amp;amp;v=3.55.2&quot; style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Ref.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/2.5D&quot;&gt;2.5D&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rgy0409.tistory.com/608&quot;&gt;아이소메트릭(isometric) 게임에 대한 설명 및 견해&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%93%B1%EC%B6%95_%ED%88%AC%EC%98%81%EB%B2%95&quot;&gt;등축 투영법&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gamedevelopment.tutsplus.com/tutorials/creating-isometric-worlds-a-primer-for-game-developers--gamedev-6511&quot;&gt;Creating Isometric Worlds: A Primer for Game Developers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/13092038/converting-x-y-grid-coordinates-to-crafty-js-isometric-coordinates/13198583&quot;&gt;Converting X,Y grid coordinates to Crafty.js Isometric Coordinates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sun, 27 Mar 2022 18:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2022/03/27/quarter-view/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2022/03/27/quarter-view/</guid>
        
        <category>2.5d</category>
        
        <category>pseudo</category>
        
        <category>isometric</category>
        
        <category>quarter-view</category>
        
        
      </item>
    
      <item>
        <title>github action / github page 기능을 이용한 static deploy</title>
        <description>&lt;h2 id=&quot;들어가며&quot;&gt;들어가며&lt;/h2&gt;
&lt;p&gt;github page 기능을 이용해서 수많은 사람들이 블로그로 애용 했습니다.
그렇지만 나는 이미지 파일 하나 올릴껀데? jekyll 블로그를 써야해? 라는 사람이 있겠죠?
그런 사람을 위해서 준비했습니다!&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;summary&lt;/h2&gt;
&lt;p&gt;webpack 을 이용해서 번들링할 예정이고, 
github action 을 통한 빌드와 배포 자동화를 진행할 예정입니다.&lt;/p&gt;

&lt;p&gt;최근에 githuab pages 가 업데이트되어 별도의 설정 메뉴로 빠졌습니다!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://docs.github.com/assets/cb-70869/images/help/pages/publishing-source-drop-down.png&quot; alt=&quot;github pages&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이번 업데이트로 특정 branch 를 github page 로 지정 가능합니다. 아래와 같이 운영할 예정입니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;gh-pages branch 를 github page 용도로 사용할 예정입니다.&lt;/li&gt;
  &lt;li&gt;main branch 는 소스코드를 저장할 용도입니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;빌드를-설정하자&quot;&gt;빌드를 설정하자&lt;/h2&gt;
&lt;p&gt;webpack 빌드 설정에 대해서는 이미 많이 다루고 있으니, 여기에서는 적지 않겠습니다. github action 을 통해서 빌드를 먼저 하도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;먼저 yml 파일을 생성합니다.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.github/workflows/deploy.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;다음과 같이 작성할 예정입니다!&lt;/p&gt;
&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build and deploy&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
  &lt;span class=&quot;na&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
    &lt;span class=&quot;na&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
  &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@main&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;set up node.js&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/setup-node@main&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;16.x&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cache node_modules&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/cache@v1&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
          &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node_modules&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$-build-$${hashFiles('**/package-lock.json')}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;restore-keys&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;$-build-$-build&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;install devDependencies&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;npm install&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;npm run prod&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;deploy&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;peaceiris/actions-gh-pages@v3&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;github_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;publish_branch&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gh-pages&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;publish_dir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./dist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;천천히 항목별로 설명 드리겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build and deploy&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
  &lt;span class=&quot;na&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
    &lt;span class=&quot;na&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;main branch 를 통해서 pipeline 이 유발되도록 세팅했습니다.&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
  &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;ubuntu 20.04 버젼 기반으로 pipeline 이 작동하기 위해서 명시합니다. &lt;a href=&quot;https://github.com/actions/virtual-environments&quot;&gt;참고&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@main&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;set up node.js&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/setup-node@main&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;16.x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;빌드를 위해서 소스코드 받아야 겠죠? checkout 구현을 위해서 steps 에 추가합니다. (actions/checkout@main)
또한 webpack 빌드를 위해서 node 를 설치합니다. (actions/setup-node@main) node-version 변수를 통해서 node 버젼 설정이 가능합니다.
지원하는 메이저 버젼은 여기에서 &lt;a href=&quot;https://github.com/actions/setup-node&quot;&gt;참고&lt;/a&gt; 하세요.&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cache node_modules&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/cache@v1&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
          &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node_modules&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$-build-$${hashFiles('**/package-lock.json')}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;restore-keys&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;$-build-$-build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 부분은 npm dependency module 설치를 캐쉬하여, gitlab action 에 실행시간을 줄여주는데 목적이 있습니다. &lt;a href=&quot;https://github.com/actions/cache&quot;&gt;참고&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;install devDependencies&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;npm install&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;npm run prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이 부분은 실제 빌드를 위한 dependency 와 빌드 명령어를 쓰는데 목적이 있습니다.
(중요하지 않아 빠르게 넘어가겠습니다!)&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;deploy&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;peaceiris/actions-gh-pages@v3&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;github_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;publish_branch&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gh-pages&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;publish_dir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./dist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이 부분이 중요 키포인트 인데요. 실제 빌드가 완료된 결과물들을 github page로 배포하기 위한 스텝입니다.&lt;/p&gt;

&lt;p&gt;먼저 저 github_token 항목은 별도로 설정이 필요한 항목이 아닙니다!&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A GitHub Actions runner automatically creates a GITHUB_TOKEN secret to authenticate in your workflow. So, you can start to deploy immediately without any configuration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;github action 이 자동적으로 생성한다고 합니다&lt;/p&gt;

&lt;p&gt;나머지 설정은 다음과 같습니다. (추가 옵션은 여기를 &lt;a href=&quot;https://github.com/peaceiris/actions-gh-pages&quot;&gt;참고&lt;/a&gt; 하세요)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;publish_branch - 빌드할 결과물들을 올릴 branch 입니다. 여기에선 gh-pages 로&lt;/li&gt;
  &lt;li&gt;publish_dir - 빌드할 결과물들이 저장될 디렉토리입니다. 각자 webpack 설정에 따라서 변경하세요. 저는 dist 로 설정했습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;github-pages-설정하기&quot;&gt;github pages 설정하기&lt;/h2&gt;

&lt;p&gt;아까 공유 드렸던 내용대로 githuab pages 가 업데이트되어 별도의 설정 메뉴로 빠졌습니다!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://docs.github.com/assets/cb-70869/images/help/pages/publishing-source-drop-down.png&quot; alt=&quot;github pages&quot; /&gt;&lt;/p&gt;

&lt;p&gt;해당 설정 페이지에서 branch 를 gh-pages 로 설정하고, 경로는 / 로 설정해주세요
(gh-branch 에서 / 디렉토리로 서비스될 예정입니다!)&lt;/p&gt;

&lt;p&gt;Ref.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site&quot;&gt;Configuring a publishing source for your GitHub Pages site&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/actions/virtual-environments&quot;&gt;GitHub Actions Virtual Environments&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/actions/checkout&quot;&gt;Checkout V3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/actions/setup-node&quot;&gt;setup-node&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/actions/cache&quot;&gt;cache&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/peaceiris/actions-gh-pages&quot;&gt;peaceiris/actions-gh-pages&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://davidyang2149.dev/front-end/github-actions%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-gh-pages-%EC%9E%90%EB%8F%99-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0/&quot;&gt;Github Actions를 이용하여 gh-pages 자동 배포하기&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://velog.io/@xxell-8/GitHub-Pages-%ED%99%9C%EC%9A%A9-GitHub-Actions%EB%A1%9C-Vue.js-%EC%9E%90%EB%8F%99-%EB%B0%B0%ED%8F%AC&quot;&gt;CI/CD ② GitHub Actions로 Vue.js 자동 배포&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 02 Mar 2022 00:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2022/03/02/github-page-static-deploy/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2022/03/02/github-page-static-deploy/</guid>
        
        <category>github</category>
        
        <category>page</category>
        
        <category>ci</category>
        
        <category>cd</category>
        
        <category>svn</category>
        
        
      </item>
    
      <item>
        <title>Apple In_App Event</title>
        <description>&lt;h2 id=&quot;소개&quot;&gt;소개&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/in_app_event_01.PNG&quot; alt=&quot;https://apple.com&quot; /&gt;&lt;/p&gt;

&lt;p&gt;인앱이벤트 기능은 iOS/iPadOS15 부터 지원하는 기능으로, 쉽게 말해 앱 내부에서 진행되는 이벤트를 앱스토어에서 노출 시킬 수 있는 기능입니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;앱스토어에서 이벤트 노출 영역들은 아래와 같습니다.&lt;/li&gt;
  &lt;li&gt;앱 페이지 내부 : 노출 설정한 모든 이벤트가 보입니다.&lt;/li&gt;
  &lt;li&gt;앱 검색 결과 : 앱을 설치하지 않은 사람은 기존 스크린샷이 보이지만, 이미 설치한 사람에게는 인앱이벤트가 보입니다. 이벤트를 직접 검색할 수도 있습니다.&lt;/li&gt;
  &lt;li&gt;투데이/게임/앱 화면 : 큐레이션과 사용자 추천 영역에 노출 될 수도 있습니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;이점&quot;&gt;이점&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;앱 내부에서 진행되는 이벤트들은 사용자가 서비스에 꾸준한 관심이 없다면 놓치게 되는 경우가 많습니다. 하지만 인앱이벤트 기능을 활용하면 현재 진행중인 이벤트를 앱 스토어에서 바로 노출 시킬 수 있습니다.&lt;/li&gt;
  &lt;li&gt;앱을 설치하지 않은 사용자의 경우, 앱 내부에서 어떤 이벤트가 진행되는지 앱을 설치하지 않고도 한 눈에 확인할 수 있습니다. 앱을 삭제했더라도 사용자에게 관심 있는 이벤트가 노출되고 있다면 재 설치를 유도할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;이미 앱을 설치한 사용자의 경우, 이벤트 카드에 삽입된 딥링크 또는 유니버셜 링크를 통해 앱 내부의 이벤트 화면으로 바로 이동 할 수 있게 됩니다. 이를 통해 이벤트 참여율을 높일수 있게 됩니다.&lt;/li&gt;
  &lt;li&gt;사용자는 미래에 열릴 이벤트에 대한 푸시 알림을 설정할 수 있고, 이벤트가 시작되면 앱 스토어에서 해당 이벤트가 시작되었다는 푸시 알림을 보내줍니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;인앱이벤트-생성-및-관리&quot;&gt;인앱이벤트 생성 및 관리&lt;/h2&gt;

&lt;p&gt;인앱이벤트 기능은 앱을 수정하지 않고도 도입할 수 있는 기능입니다. iOS 앱을 관리하는 사이트인 App Store Connect 사이트에서 생성과 관리가 가능합니다.
&lt;img src=&quot;/files/posts/in_app_event_02.PNG&quot; alt=&quot;https://apple.com&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;기간설정&quot;&gt;기간설정&lt;/h2&gt;

&lt;p&gt;인앱이벤트는 이벤트 시작일 이전 14일부터 노출 설정이 가능하며, 이벤트 기간은 최대 31일 까지 설정할 수 있습니다.
이벤트 기간이 끝나면 검색 및 노출은 불가능하지만, 앱 스토어 링크를 가지고 있는 사용자는 확인이 가능합니다.&lt;/p&gt;

&lt;h2 id=&quot;지역화&quot;&gt;지역화&lt;/h2&gt;

&lt;p&gt;이벤트 정보는 지역화가 가능합니다. 내부 문구들을 각각의 언어에 맞는 내용들로 채워넣을 수 있습니다. 참여할 수 있는 국가 정보를 따로 설정 할 수도 있습니다. 다만 앱이 출시된 국가에 한정하여 설정이 가능합니다.&lt;/p&gt;

&lt;h2 id=&quot;딥링크&quot;&gt;딥링크&lt;/h2&gt;

&lt;p&gt;이벤트 생성시, 딥 링크를 설정하면 앱 스토어에서 앱 내부 이벤트 화면으로 바로 이동할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;심사&quot;&gt;심사&lt;/h2&gt;

&lt;p&gt;인앱이벤트를 새로 생성하였을 때는 앱 리뷰팀의 심사를 받아야 하지만, 앱 업데이트와는 별개로 진행되기 때문에 새로운 이벤트를 등록하기 위해 업데이트를 올린다거나 빌드를 추가로 생성할 필요가 없습니다.&lt;/p&gt;

&lt;p&gt;한 앱에 최대 5개의 이벤트를 노출시킬 수 있고, 미리 심사를 받아놓는 건 10개까지 가능합니다. 이 10개는 현재 노출된 이벤트를 포함한 갯수입니다.&lt;/p&gt;

&lt;h2 id=&quot;통계&quot;&gt;통계&lt;/h2&gt;

&lt;p&gt;인앱이벤트 에 대한 통계 확인은 App Store Connect 사이트 내에서 가능합니다. 확인이 가능한 항목들은 아래와 같습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;이벤트 페이지 보기&lt;/li&gt;
  &lt;li&gt;미리 알림 및 알림 데이터&lt;/li&gt;
  &lt;li&gt;인앱 이벤트로 인해 발생한 다운로드&lt;/li&gt;
  &lt;li&gt;재 다운로드 수를 포함하여 인앱 이벤트&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/app-store/in-app-events/&quot;&gt;https://developer.apple.com/app-store/in-app-events/&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 24 Jan 2022 10:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2022/01/24/in_app_event/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2022/01/24/in_app_event/</guid>
        
        
      </item>
    
      <item>
        <title>svn 사용자를 위한 git 안내서</title>
        <description>&lt;h2 id=&quot;들어가며&quot;&gt;들어가며&lt;/h2&gt;
&lt;p&gt;여태까지 많은 git 안내서가 있지만, 이번에는 subversion (aka: svn) 사용자를 위한 타겟으로 글을 작성해보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Apache_Subversion_logo.svg/1200px-Apache_Subversion_logo.svg.png&quot; alt=&quot;subversion&quot; /&gt;
&lt;img src=&quot;https://media.vlpt.us/images/_seeul/post/a13ec304-4219-49f9-b294-145e79459532/img.jpeg&quot; alt=&quot;git&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;git-의-주요한-특징&quot;&gt;git 의 주요한 특징&lt;/h2&gt;
&lt;p&gt;먼저 git 은 subversion 과 달리 로컬에서도 원격에서도 저장이 됩니다. (원격 저장소를 여러개 두는 것도 가능하지만 여기서 다루지는 않겠습니다.)
그러다보니 commit 만 하고 끝이지 않냐? 라는 관성 때문에 많이들 고생하시고 계십니다..
이번은 주요한 소스 올리기와 공유 에 중점으로 다뤄보겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;데이터-받아오기&quot;&gt;데이터 받아오기&lt;/h2&gt;
&lt;p&gt;svn 의 checkout 명령어 처럼 git 의 저장소를 가져오는 명령어는 clone 입니다.&lt;/p&gt;

&lt;p&gt;로컬 저장소를 복제(clone)하려면 아래 명령을 실행하세요.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone /로컬/저장소/경로
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;원격 서버의 저장소를 복제하려면 아래 명령을 실행하세요.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone 사용자명@호스트:/원격/저장소/경로
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;데이터-가져오기&quot;&gt;데이터 가져오기&lt;/h2&gt;
&lt;p&gt;svn 의 update 명령어 처럼 git 의 저장소에서 데이터를 가져오는 명령어는 pull 입니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git pull
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;데이터-저장하기&quot;&gt;데이터 저장하기&lt;/h2&gt;
&lt;p&gt;svn 의 add / commit 명령어 처럼 git 의 저장소로 데이터를 저장하는 명령어는 git 도 동일합니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;하지만 svn 과 다르게 한가지 동작이 더 필요합니다&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;기존 svn 에서는 다음의 명령어이면 서버로 업로드하는것이 끝나지만&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;svn add &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--force&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;svn commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;add files&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;git 에서는 다음의 명령어이면 &lt;strong&gt;로컬 저장소&lt;/strong&gt; 로 저장이 됩니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git add &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;add files&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이후로 서버에 업로드 하기 위해서는 다음의 명령어가 더 필요합니다!&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git push origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;그리고-나머지들&quot;&gt;그리고 나머지들&lt;/h2&gt;

&lt;p&gt;git 은 svn 과 달리 merge / branch 생성이 비교적 쉽습니다. 하지만 이 단계에서 이야기할 것은 아닌 것 같습니다.&lt;/p&gt;

&lt;p&gt;Ref.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://bravenamme.github.io/2021/09/01/Git/&quot;&gt;git 이해하기&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bravenamme.github.io/2019/06/11/git-tutorial/&quot;&gt;git tutorial&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rogerdudler.github.io/git-guide/index.ko.html&quot;&gt;git - 간편 안내서&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.abel9999.com/2020/05/svn-git.html&quot;&gt;svn 사용자의 git 사용 후기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 24 Jan 2022 00:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2022/01/24/svn-to-git/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2022/01/24/svn-to-git/</guid>
        
        <category>git</category>
        
        <category>svn</category>
        
        
      </item>
    
      <item>
        <title>Github Action Basic</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;github 에서 제공하는 공식 hello-world 튜토리얼을 진행하면서 적는 일지.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://lab.github.com/githubtraining/github-actions:-hello-world&quot;&gt;https://lab.github.com/githubtraining/github-actions:-hello-world&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;배우게-될-것&quot;&gt;배우게 될 것&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;workflow file을 구성하는 방법&lt;/li&gt;
  &lt;li&gt;실행가능한 script를 추가하는 방법&lt;/li&gt;
  &lt;li&gt;workflow와 action blocks를 만드는 방법&lt;/li&gt;
  &lt;li&gt;workflow를 실행시키는 방법&lt;/li&gt;
  &lt;li&gt;workflow log를 확인하는 방법&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
  &lt;p&gt;Github action은 무엇인가?&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;테스트 자동화 (CI)&lt;/li&gt;
    &lt;li&gt;CD&lt;/li&gt;
    &lt;li&gt;github의 이슈, @멘션, 라벨 등을 이용한 workflow trigger&lt;/li&gt;
    &lt;li&gt;코드리뷰 진행&lt;/li&gt;
    &lt;li&gt;브랜치 관리&lt;/li&gt;
    &lt;li&gt;이슈, PR관리&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;라고 한다..&lt;/p&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
  &lt;p&gt;Actions and Workflows&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;액션과 워크플로우에 대한 설명&lt;/li&gt;
    &lt;li&gt;깃헙액션에는 2개의 컴포넌트가 있는데 그것이 바로
      &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;action&lt;/strong&gt; 그 자체&lt;/li&gt;
        &lt;li&gt;action을 이용하는 &lt;strong&gt;workflow&lt;/strong&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;workflow는 여러개의 action을 가질 수 있고,  action은 그 자체의 목적이 있다.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;action의-종류&quot;&gt;Action의 종류&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;container actions
    &lt;ul&gt;
      &lt;li&gt;Docker &lt;strong&gt;container actions&lt;/strong&gt;는 github에서 호스팅한 linux 환경에서 실행되는 실행환경이다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;javascript actions
    &lt;ul&gt;
      &lt;li&gt;github-action code를 환경에서 떼어서(decouple)  빠르게 실행하고 의존성을 관리하도록 한다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;의 2가지로 구분될 수 있다.&lt;/p&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
  &lt;p&gt;STEP 1: Add a Dockerfile&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;여기서 만드는 action은 도커 컨테이너를 이용하므로 dockerfile이 필요하다.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;aside&gt;
💡 **action-a/Dockerfile** 을 작성하고, 깃헙 repo에 PR을 열어보자

&lt;/aside&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; debian:9.5-slim&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ADD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; entrypoint.sh /entrypoint.sh&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; +x /entrypoint.sh
&lt;span class=&quot;k&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;/entrypoint.sh&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;PR 여는 방법
    &lt;ul&gt;
      &lt;li&gt;새 branch를 생선한다. (&lt;strong&gt;first-action 브랜치&lt;/strong&gt;)&lt;/li&gt;
      &lt;li&gt;action-a 디렉토리를 생성하고, Dockerfile을 작성한다.&lt;/li&gt;
      &lt;li&gt;커밋을 진행하고 repo에 push한다.&lt;/li&gt;
      &lt;li&gt;main 브랜치에 대해 PR을 연다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;위에서 /entrypoint.sh 스크립트는 Docker에서 실행될 것이며, 여기에는 action이 실제로 하고자 하는게 명세될 것임.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
  &lt;p&gt;STEP 2: Add an entrypoint script&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;action이 Docker를 이용해 실행시킬 entrypoint.sh 파일을 실제로 repo에 만들어야 한다.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;aside&gt;
💡 **entrypoint.sh** 파일을 작성하고 first-action 브랜치에 푸시한다.

&lt;/aside&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh -l&lt;/span&gt;
sh -c &quot;echo Hello world my name is $INPUT_MY_NAME&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;이제 이 스크립트를 실행시키기 위해서는 docker 를 트리거할 수 있는 github-action이 필요하다.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
  &lt;p&gt;STEP 3: Add an action metadata file&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;input 파라미터를 MY_NAME 값을 읽기위해 이용한다&lt;/li&gt;
    &lt;li&gt;아래와 같은 파일을 action-a/action.yml 로 추가한다&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Hello&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Actions&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Greet&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;someone&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;octocat@github.com&quot;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;MY_NAME&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Who&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;greet&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;World&quot;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;runs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docker&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Dockerfile&quot;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;branding&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;mic&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;purple&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
  &lt;p&gt;STEP 4: Start your workflow file&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;workflow 는 .github/workflows 디렉토리 아래에 main.yml 로 정의된다.&lt;/li&gt;
    &lt;li&gt;workflow는 특정 이벤트에 기반해 실행되며, 이 실습에서는 push 이벤트에 대해 실행되도록 해 본다.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;.github/workflows/main.yml 파일 생성&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;A workflow for my Hello World file&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;name: A workflow for my Hello World file
    &lt;ul&gt;
      &lt;li&gt;각 워크플로에 대해 특정한 이름을 정해줄 수 있다.&lt;/li&gt;
      &lt;li&gt;이 값은 action탭이나 각 PR에서 확인할 수 있다.&lt;/li&gt;
      &lt;li&gt;특정 repo안에 여러개의 workflow가 있는 경우 유용하다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;on: push
    &lt;ul&gt;
      &lt;li&gt;이 워크플로가 언제 실행될 것인지를 지칭&lt;/li&gt;
      &lt;li&gt;이 경우는 push event가 발생하는 경우이다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;aside&gt;
💡 - workflows
    - jobs
        -steps

의 구조로 이루어져 있다.

&lt;/aside&gt;

&lt;ul&gt;
  &lt;li&gt;이번에는 action을 실행시키는 job을 만들어 보자.&lt;/li&gt;
  &lt;li&gt;actions는 다음과 같은 곳에서 이용될 수 있다.
    &lt;ul&gt;
      &lt;li&gt;같은 repo&lt;/li&gt;
      &lt;li&gt;다른 public repo&lt;/li&gt;
      &lt;li&gt;docker container image&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;여기서는 이 repo에서 실행시켜 본다.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
  &lt;p&gt;STEP 5: Run an action from your workflow file&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;위에서 만들었던 .github/workflows/main.yml 파일에 job 명세를 추가해보자&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Hello world action&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@v1&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./action-a&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;MY_NAME&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Mona&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;jobs
    &lt;ul&gt;
      &lt;li&gt;workflow 실행의 기본 단위(component)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;build
    &lt;ul&gt;
      &lt;li&gt;이 job에 붙이는 식별자(identifier)&lt;/li&gt;
      &lt;li&gt;자유롭게 줄수 있는 이름인 듯 (?)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;name
    &lt;ul&gt;
      &lt;li&gt;이 job의 이름. 워크플로 실행시 github에서 확인되는 이름이다&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;img src=&quot;/files/posts/20220113/github-action-01.png&quot; alt=&quot;이런식으로&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;이런식으로&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;runs-on
    &lt;ul&gt;
      &lt;li&gt;이 job을 실행할 머신의 종류&lt;/li&gt;
      &lt;li&gt;github-hosted runner일 수도 있고, self-hosted runner일 수도 있다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;steps
    &lt;ul&gt;
      &lt;li&gt;job을 수행하기 위한 linear sequence&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;uses: actions/checkout@v1
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;checkout&lt;/strong&gt; 이라는 이름의 community action에게 이 repo에 접근할 수 있도록 해 준다.&lt;/li&gt;
      &lt;li&gt;즉 저 공개된 action을 이용한다는 뜻으로 보임&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;uses: ./action-a
    &lt;ul&gt;
      &lt;li&gt;상대경로로 우리가 만들어둔 action-a 디렉토리의 action을 이용하겠다&lt;/li&gt;
    &lt;/ul&gt;

    &lt;aside&gt;
  💡 이때 상대경로가 지금 이 workflow를 실행하는 main.yml의 경로로부터 시작되는게 아니라 root에서 job이 실행된다는 것으로 보인다.
    
  &lt;/aside&gt;
  &lt;/li&gt;
  &lt;li&gt;with
    &lt;ul&gt;
      &lt;li&gt;runtime에 이용할 입력변수를 지정한다.&lt;/li&gt;
      &lt;li&gt;이 경우에는 MY_NAME 이라는 변수에 “Mona” 라는 값을 할당했다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;총정리&lt;/strong&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;github-action은 github repo에 발생하는 특정 event를 감지해 workflow를 실행 시키는 일련의 작업을 말한다.&lt;/li&gt;
    &lt;li&gt;Github-Actions는 일종의 상품명 같은 느낌이고 실제적인 action으로 볼 수 있는 구체적은 항목들은 workflow라고 부른다.&lt;/li&gt;
    &lt;li&gt;workflow의 구성은 .github/workflows/ 디렉토리에 정의할 수 있으며, 지금까지는 main.yml 파일을 통해 정의했으나 복수개의 파일로도 가능할 것 같다. (아직 모름)&lt;/li&gt;
    &lt;li&gt;workflow는 복수개의 job 들로 이루어져 있다.&lt;/li&gt;
    &lt;li&gt;job은 복수개의 step들로 이루어져 있다.&lt;/li&gt;
    &lt;li&gt;위 실습의 최종 결과는 다음과 같다&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20220113/github-action-02.png&quot; alt=&quot;무엇이든 push가 발생하면 workflow가 실행된다.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20220113/github-action-03.png&quot; alt=&quot;Hello world action 이라는 이름의 job 실행, checkout과 action-a의 step이 실행된다.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20220113/github-action-04.png&quot; alt=&quot;docker 컨테이너를 이용해 entrypoint.sh 파일이 실행된 모습. 실행변수로 넘긴 Mona도 잘 적용 되었다.&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 12 Jan 2022 20:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2022/01/12/github-action/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2022/01/12/github-action/</guid>
        
        <category>github</category>
        
        
      </item>
    
      <item>
        <title>php8 에 도입되는 annotation (attributes)</title>
        <description>&lt;h2 id=&quot;php8-에-도입되는-attributes&quot;&gt;php8 에 도입되는 attributes&lt;/h2&gt;
&lt;p&gt;php 8 부터는 attrubutes 라는 기능을 사용할 수 있습니다. 다른 많은 언어에서는 annontation 이라고 불리는 것인데, 이 attributes (aka. annotation) 은 앞서, rman 님께서 작성해주신 &lt;a href=&quot;/2021/11/10/Annotation/&quot;&gt;Annotation 이해하기&lt;/a&gt; 을 참조해주세요.&lt;/p&gt;

&lt;p&gt;(이미 php8 소개하는 많은 블로그들이 있었서 늦은감이 있네요…)&lt;/p&gt;

&lt;p&gt;일단 여기서는 어떻게 사용하는지, 또 어떻게 커스텀 attributes 를 만드는지 등에 대해서 다뤄 보겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;개요&quot;&gt;개요&lt;/h2&gt;
&lt;p&gt;먼저 attribute 가 작성된 예제를 올려봅니다.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Support\Attributes\ListensTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProductSubscriber&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#[ListensTo(ProductCreated::class)]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;onProductCreated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ProductCreated&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* … */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;#[ListensTo(ProductDeleted::class)]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;onProductDeleted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ProductDeleted&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* … */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;뒷부분에 실제 사용하는 다른 코드를 보여드리겠습니다만. 이 코드가 attirbutes 를 가장 설명하기 좋은 예라고 생각합니다.&lt;/p&gt;

&lt;p&gt;이 문법이 여러분들이 기대했던 것이 아닐 수도 있습니다. 보통 @ 혹은 @: /* */  같은 주석을 선호할 수 도 있습니다. 사실 이런 문법에 대한 논쟁들은 php rfc 에 대한 토론을 읽어보길 권장 드립니다. &lt;a href=&quot;https://externals.io/message/110640&quot;&gt;PHP RFC: Shorter Attribute Syntax&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;일단 코드에 집중 하도록 하겠습니다. 저 &lt;strong&gt;ListensTo&lt;/strong&gt; 는 어떻게 작동할가요?&lt;/p&gt;

&lt;p&gt;이제 보여 드릴 custom attributes 는 &lt;strong&gt;#[Attributes]&lt;/strong&gt; 라는 attribute 가 선언된 간단한 클래스 입니다. 이 기본 attribute 는 원래 PhpAttribute 라고 RFC 에서 결정하였지만, 나중에 다른 토론을 통해 변경 되었습니다.  &lt;a href=&quot;https://wiki.php.net/rfc/attribute_amendments&quot;&gt;PHP RFC: Attribute Amendments&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;custom attribute 는 다음과 같이 작성됩니다.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#[Attribute]&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ListensTo&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;간단하죠? custom attribute 를 작성하신다면 목표를 한정해서 작성하세요. attribute 는 클래스와 메소드에 메타데이터를 추가하기 위한 것이며, 그 이상은 아닙니다.&lt;/p&gt;

&lt;p&gt;예를 들어 parameter 입력 유효성 검사에 사용할 수 없습니다.&lt;/p&gt;

&lt;p&gt;즉 attribute 내에서 메소드에 전달된 parameter 에는 접근할 수 없습니다.&lt;/p&gt;

&lt;p&gt;원래는 이 동작을 허용하는 이전 RFC 가 있었지만 이후 논의를 통해 제외 되었습니다.&lt;/p&gt;

&lt;p&gt;아까 event subscriber 예제를 다시 보자면, 여전히 meta data 를 읽고 어딘가의 subscriber 들에게 전달하여야 합니다.&lt;/p&gt;

&lt;p&gt;좀 더 내용을 추가하기 위해, 지루한 boilerplate 코드를 몇개 작성해봅시다.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EventServiceProvider&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServiceProvider&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// In real life scenarios, &lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//  we'd automatically resolve and cache all subscribers&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//  instead of using a manual array.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$subscribers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ProductSubscriber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// The event dispatcher is resolved from the container&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$eventDispatcher&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;EventDispatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subscribers&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$subscriber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// We'll resolve all listeners registered &lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;//  in the subscriber class,&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;//  and add them to the dispatcher.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;resolveListeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$subscriber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
                &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$listener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$eventDispatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$listener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;       
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;       
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;[$event, $listener]&lt;/strong&gt; 문법이 친숙하지 않을 수 있겠지만, 코드 생산성을 높이기 문법입니다. (배열 구조 분해 / ES6 를 생각해보세요!)&lt;/p&gt;

&lt;p&gt;이제 resolveListeners 를 한번 보실까요!&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolveListeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$subscriberClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$reflectionClass&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ReflectionClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$subscriberClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;$listeners&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$reflectionClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getMethods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ListensTo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$attributes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$listener&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$attribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;newInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            
            &lt;span class=&quot;nv&quot;&gt;$listeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// The event that's configured on the attribute&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$listener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    
                &lt;span class=&quot;c1&quot;&gt;// The listener for this event &lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$subscriberClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()],&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$listeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ReflectionMethod::getAttributes()&lt;/strong&gt; 를 통해 주석 문자열을 parsing 하는 것보다 메타 데이터를 쉽게 읽을 수 있는 것을 확인할 수 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;역주 : php 8 이전에는 annotation 을 문법적으로 지원하지 못해, php 소스코드의 주석을 string 으로 parsing 해서 구현하였습니다. ㅎㄷㄷ &lt;a href=&quot;https://www.php.net/manual/en/reflectionproperty.getdoccomment&quot;&gt;ReflectionProperty::getDocComment&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;좀 어려운 포인트가 두가지 있는데요, 한번 정리해보겠습니다.&lt;/p&gt;

&lt;p&gt;먼저 &lt;strong&gt;$attribute-&amp;gt;newInstance()&lt;/strong&gt; 호출이 있습니다. 이 코드는 실제로 우리가 작성한 custom attribute 를 인스턴스화되는 장소입니다. 우리가 작성한 subscriber 클래스의 attribute 에 나열된 매개 변수를 사용하여 생성자에 전달합니다.&lt;/p&gt;

&lt;p&gt;즉, 기술적으로는 custom attribute 에 매개 변수를 전달할 필요가 없습니다. 물론 &lt;strong&gt;$attribute-&amp;gt;getArguments()&lt;/strong&gt; 를 직접 호출할 수 있습니다. 또한 클래스를 인스턴스화한다는 것은 원하는 방식으로 구문 분석 입력을 생성할 수 있다는 것을 의미합니다. 대체로 &lt;strong&gt;newInstance()&lt;/strong&gt;를 사용하여 속성을 인스턴스화하는 것이 좋습니다.&lt;/p&gt;

&lt;p&gt;두번째로 &lt;strong&gt;ReflectionMethod::getAttributes()&lt;/strong&gt; 를 이용한 메쏘드의 모든 attributes 를 반환하는 함수의 사용입니다. 두가지 parameter 를 사용하여 반환값 필터링할 수 있습니다. 자세한건 아래 문서를 확인해주세요. &lt;a href=&quot;https://www.php.net/manual/en/reflectionfunctionabstract.getattributes.php&quot;&gt;ReflectionFunctionAbstract::getAttributes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;이 필터링을 이해하려면 먼저 attributes 에 대해서 알아야 할 것이 한 가지 더 있습니다. method 뿐만 아니라 class, property 또는 constant에 여러 attribute 을 추가할 수 있다는 것입니다.&lt;/p&gt;

&lt;p&gt;아래는 class 에 선언된 예제입니다.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#[Route(Http::POST, '/products/create'), Autowire,]&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProductsCreateController&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__invoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* … */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이를 염두에 두시고 &lt;strong&gt;Reflection::getAttributes()&lt;/strong&gt; 가 배열을 반환하는 이유가 명확하므로 결과를 필터링하는 방법을 살펴보겠습니다.&lt;/p&gt;

&lt;p&gt;여기에서는 controller 의 route 를 parsing 하는것에 촛점을 맞추고
Route attribute 에 대해서만 관심을 가지도록 하겠습니다. 해당 클래스를 필터로 쉽게 전달 할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$reflectionClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;두번째 parameter는 필터링이 수행되는 방식을 변경합니다. 지정된 인터페이스를 구현하는 모든 속성을 반환하도록 하는  ReflectionAttribute::IS_INSTANCEOF 를 전달할 수 있습니다.&lt;/p&gt;

&lt;p&gt;예를 들어 여러 attribute 에 의존하는 컨테이너 정의를 구문을 parsing 한다고 가정한다면…&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$reflectionClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;ContainerAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;nc&quot;&gt;ReflectionAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;IS_INSTANCEOF&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;좀 더 풀어서 쉽게 설명드리자면… class 아래의 모든 하위 method, property, constants 의 attribute 를 가져올때 선언하면 됩니다.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$r_atts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$rc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;SomeAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 0 is default, just given class&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;json_encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;array_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ReflectionAttribute&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$r_att&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$r_att&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$r_atts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;PHP_EOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$r_atts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$rc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;SomeAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// given class and children classes&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;json_encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;array_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ReflectionAttribute&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$r_att&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$r_att&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$r_atts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;PHP_EOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;real-world&quot;&gt;Real World&lt;/h2&gt;

&lt;p&gt;그렇다면 실제 활용할 수 있는 예제는 무엇일까요?&lt;/p&gt;

&lt;p&gt;laravel 을 예를 들면, php7 까지의 laravel 에서 route 를 등록하기 위해 route 에 대한 설정값이 존재하였습니다. &lt;a href=&quot;https://laravel.kr/docs/8.x/routing&quot;&gt;라우팅&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;routes 라는 디렉토리의 web.php / api.php 에 연결할 컨트롤러를 등록하는 형식이었죠.
아래와 같이요.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'user/profile'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;UserProfileController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'show'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'profile'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;하지만 php attributes 에 대한 도입으로 이런 설정 파일을 따로 작성할 필요가 없어졌습니다. &lt;a href=&quot;https://github.com/spatie/laravel-route-attributes&quot;&gt;laravel-route-attributes&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spatie\RouteAttributes\Attributes\Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserProfileController&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#[Get('user/profile')]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;설정 파일을 통하지 않고, 컨트롤러에 attribute 작성하는 것 만으로도 충분하게 되었죠.&lt;/p&gt;

&lt;p&gt;이상입니다.&lt;/p&gt;

&lt;p&gt;Ref.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://stitcher.io/blog/attributes-in-php-8&quot;&gt;PHP 8: Attributes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/spatie/laravel-route-attributes&quot;&gt;laravel-route-attributes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://pronist.tistory.com/60&quot;&gt;PHP: PHP 8 기능 정리 및 요약 - 개발자 정상우&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://velog.io/@qroffle/PHP-%EC%86%8C%EC%8B%9D-Attribute&quot;&gt;PHP 소식 - Attribute&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 01 Dec 2021 10:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2021/12/01/php8_attributes/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2021/12/01/php8_attributes/</guid>
        
        <category>php</category>
        
        <category>annotation</category>
        
        
      </item>
    
      <item>
        <title>pessimistic lock, optimistic lock</title>
        <description>&lt;h3 id=&quot;비관적-락pessimistic-lock&quot;&gt;비관적 락(pessimistic lock)&lt;/h3&gt;

&lt;p&gt;비관적 락이란 트랜잭션의 시작에 S Lock, X Lock 을 걸고 시작하는 방법 입니다. DB 에 write 를 하기 위해서는 X Lock 을 받아야 하는데 이미 S Lock 이 다른 트랜잭션에 걸려 있어 write 를 위한 Lock 을 얻지 못하므로 앞선 트랜잭션이 종료되기 전까지 수정할 수 없습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/202111/fig1.png&quot; alt=&quot;fig1. 비관적락의 예&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;낙관적-락optimistic-lock&quot;&gt;낙관적 락(optimistic lock)&lt;/h3&gt;

&lt;p&gt;낙관적 락은 DB 자체에서 제공되는 락이 아닌 Application Level 에서 주어지는 Lock 입니다.  같은 조건의 경우로 두 건의 트랜잭션이 발생한다고 가정 했을 때, 하나의 트랜잭션이 먼저 commit 까지 마치고 트랜잭션을 종료하게 되면 이후에 같은 조건으로 발생된 트랜잭션은 변경된 값에 의해  동일한 조건으로는 값 수정을 할 수 없게 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/202111/fig2.png&quot; alt=&quot;fig2. 낙관적락의 예&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;롤백&quot;&gt;롤백&lt;/h3&gt;

&lt;p&gt;업데이트 하는 테이블이 2개의 테이블로 구성되었고, 2번째 테이블 업데이트시 충돌이 발생하여 롤백이 발생한다면 비관적락과 낙관적 락은 다른 처리를 하게 됩니다.&lt;/p&gt;

&lt;p&gt;비관적 락의 경우 하나의 트랜잭션으로 묶여있기 때문에 수정이 하나 실패하면 database 단에서 해당 트랜잭션 전체에 자동으로 Rollback이 일어나게됩니다.&lt;/p&gt;

&lt;p&gt;![fig3. 비관적락과 롤백]](/files/posts/202111/fig3.png)&lt;/p&gt;

&lt;p&gt;낙관적 락은 Transaction 을 잡지 않기 때문에 만약 충돌이 발생하여 수정을 못한 부분에 대해서는 Application 단에서 롤백에 대한 책임을 지며 Application에서 수동으로 롤백 해줘야 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/202111/fig4.png&quot; alt=&quot;fig4. 낙관적락과 롤백&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;optimistic-vs-pessimistic&quot;&gt;Optimistic VS Pessimistic&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;충돌이 자주 발생하는 상황인가?&lt;/li&gt;
  &lt;li&gt;읽기와 수정중 어느곳에 중점을 두고 있는가?&lt;/li&gt;
  &lt;li&gt;웹 어플리케이션은 Optimistic Lock 을 주로 사용한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;낙관적락은 성능상 유리하지만 충돌 발생시 롤백을 개발자가 직접 처리해야 하기 때문에 트랜잭션 롤백이 발생하는 비관적락 에 비해서 불리합니다. 따라서 충돌이 많이 발생되지 않고 이를 해결하기 위한 비용이 많지 않은 곳에 사용하는 것이 유리 합니다.&lt;/p&gt;

&lt;p&gt;JPA(hibernate)를 사용한 경우 충돌이 발생한 이와같은 상황에서 Optimistic Lock Exception을 던져주기 때문에 어플리케이션 단에서 충돌이 발생 했음을 인지 가능하며 예외 처리가 가능 합니다. (entity 생성시 column 으로 사용될 값에 @version 을 사용하여 동작 가능)&lt;/p&gt;

&lt;h3 id=&quot;exclusive-lock-x-lock&quot;&gt;Exclusive Lock (X Lock)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;X Lock 은 write 에 대한 Lock&lt;/li&gt;
  &lt;li&gt;SELECT … FOR UPDATE, UPDATE, DELETE 등 수정 쿼리 수행시 각 ROW 에 걸리는 LOCK&lt;/li&gt;
  &lt;li&gt;X Lock 이 걸려있으면 다른 트랜잭션은 S Lock, X Lock 둘 다 걸 수 없다. (read 도 불가능)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;shared-lock-s-lock&quot;&gt;Shared Lock (S Lock)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;S Lock 은 read 에 대한 Lock&lt;/li&gt;
  &lt;li&gt;DB에 쿼리할 때 lock in share mode; 를 뒤에 명시 하면 S Lock 을 걸 수 있다.(8.0 기준, FOR SHARE 도 가능)&lt;/li&gt;
  &lt;li&gt;S Lock 이 걸려 있을때 X Lock 은 걸 수 없다. 즉 write 가 발생할 수 없다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;innodb-에서-lock-을--확인하는-방법&quot;&gt;innodb 에서 Lock 을  확인하는 방법&lt;/h3&gt;

&lt;div class=&quot;language-scss highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;information_schema&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;.INNODB_LOCKS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ref. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://sabarada.tistory.com/175&quot;&gt;https://sabarada.tistory.com/175&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://jinhanchoi1.medium.com/%EB%B9%84%EA%B4%80%EC%A0%81-lock-%EB%82%99%EA%B4%80%EC%A0%81-lock-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-1986a399a54&quot;&gt;https://jinhanchoi1.medium.com/비관적-lock-낙관적-lock-이해하기-1986a399a54&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=onBpJRDSZGA&quot;&gt;https://www.youtube.com/watch?v=onBpJRDSZGA&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 25 Nov 2021 10:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2021/11/25/db_lock/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2021/11/25/db_lock/</guid>
        
        <category>db</category>
        
        <category>lock</category>
        
        
      </item>
    
      <item>
        <title>구글이 안드로이드 앱 배포를 AAB로 변경</title>
        <description>&lt;p&gt;앱 배포 파일 확장자로 iOS 앱에는 .ipa가, 안드로이드 앱에는 .apk가 붙는다. &lt;br /&gt;
작년 2020년 11월, 구글은 2021년 8월부터 ‘구글 플레이에 새로 올라오는 모든 안드로이드 앱은 AAB 형식이어야 한다’며 스토어 정책을 바꿨다 &lt;br /&gt;
기존 앱들은 똑같이 APK로 배포되어도 상관없지만 새로 업로드되는 앱들은 모두 AAB 형식으로 스토어에 올라와야 한다는 내용이다.&lt;br /&gt;
이번 글에서는 AAB가 정확히 무엇인지, 구글의 새 정책이 어떤 변화를 가져올지 살펴보자.&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;aab는-뭘까&quot;&gt;AAB는 뭘까?&lt;/h2&gt;
&lt;p&gt;APK(Android Package)는 이미 완성된 안드로이드 앱 파일이고, &lt;br /&gt;
AAB(Android App Bundle)는 APK를 완성해주는 요소를 담은 패키지다.&lt;br /&gt;
&lt;img src=&quot;/files/posts/20211115/image001.png&quot; alt=&quot;출처 : https://android-developers.googleblog.com/  안드로이드 개발자 블로그.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;각 언어별 values, 디바이스 해상도 별 이미지 등을 기존처럼 모든 기기에 대응할 수 있는 하나의 APK를 전달하는 것이 아니라, &lt;br /&gt;
개발자가 스토어에 AAB 패키지를 올려놓으면, 스토어가 사용자 기기에 어떤 내용이 필요한지 확인 후 그에 맞춘 APK 파일을 만들어 배포하는 방식이다.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20211115/image002.png&quot; alt=&quot;출처 : https://android-developers.googleblog.com/  안드로이드 개발자 블로그.&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;aab장점&quot;&gt;AAB장점?&lt;/h2&gt;
&lt;p&gt;구글 AAB 장점 앱의 크기가 줄어든다는 것이 가장 큰 장점이다. &lt;br /&gt;
개발자가 각 사용자들에게 맞는 APK 파일 버전을 여러 개 만들어 배포하는 것이 가장 좋다.&lt;br /&gt;
하지만 그러기엔 세상에 안드로이드 기기의 종류와 언어가 너무 많다.&lt;br /&gt;
그리고 업데이트가 있을 때마다 그 모든 버전을 최신화한다는 것은 물리적으로 불가능하다.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;스토어 측에서 각 사용자에게 맞는 블록만 모아서 조립 후 배포하는 식이다. &lt;br /&gt;
이러면 개발자 입장에서는 일일이 맞춤형으로 제작하지 않아도 되고, &lt;br /&gt;
사용자 입장에서는 필요 없는 기능은 받지 않아도 된다. &lt;br /&gt;
참고로 AAB 형태로 배포하면 앱 크기가 평균 15% 줄어든다고 한다. &lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;무조건-좋아-보이는데-단점은-없나&quot;&gt;무조건 좋아 보이는데, 단점은 없나?&lt;/h2&gt;
&lt;p&gt;구글 AAB 단점 보안에 대한 우려가 있다. &lt;br /&gt;
모든 안드로이드 앱에는 개발자의 서명 파일이 들어간다. &lt;br /&gt;
서명을 하여 ‘이 앱을 만든 사람은 나’라는 증거를 남기는 것이다. &lt;br /&gt;
서명 파일은 개발자가 APK 파일에 직접 첨부한다. &lt;br /&gt;
따라서 누군가가 앱을 멋대로 변형해 배포하려고 해도, 원래 개발자의 서명이 없기 때문에 공식 앱이 아님을 확인할 수 있다. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;하지만 AAB 파일은 완성된 앱이 아니라 완성품으로 태어날 수 있는 블록의 모음이다. &lt;br /&gt;
그리고 사용자를 위해 블록을 끼워 맞추는 것은 개발자가 아니라 구글 플레이다. &lt;br /&gt;
따라서 서명은 개발자가 아닌 구글 플레이가 대신하게 된다. &lt;br /&gt;
마치 부동산 계약할 때 대리인이 서명할 수 있는 것처럼, &lt;br /&gt;&lt;br /&gt;
AAB로 배포되면 필연적으로 구글 플레이가 대리 서명을 하게 되는 것이다. &lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;구글-aab-강제&quot;&gt;구글 AAB 강제&lt;/h2&gt;
&lt;p&gt;‘사용자들에게 딱 필요한 코드만 제공해 앱 용량을 줄이고, 개발자들은 여러 개의 빌드를 준비할 필요가 없다’라는 것이 명분이지만, 안드로이드 앱은 iOS 앱과는 다르게 스토어 종류가 굉장히 많다. &lt;br /&gt;
반드시 구글 플레이를 통해 다운로드할 필요가 없다. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;이렇게 되면 구글이 스토어 수수료를 떼 가기 힘들어진다.&lt;br /&gt; 
어떻게든 구글 플레이 스토어를 통해 설치가 되어야 구글이 인앱 결제 수수료를 가져갈 수 있다. &lt;br /&gt;
AAB 형식을 강제하면 최종 파일은 구글 플레이 서버에서 만들어지고 서명되어 배포되기 때문에, 배포를 컨트롤하는 힘이 구글 쪽으로 쏠릴 수밖에 없다.&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;결론&quot;&gt;결론&lt;/h2&gt;
&lt;p&gt;안드로이드 앱의 AAB 형식은 2018년에 처음 등장하였고, 업데이트 대상 앱도 2021년 11월부터 강제화 되었습니다.&lt;br /&gt;&lt;br /&gt;
구글 플레이에 올라오는 앱은 무조건 AAB 형식으로 올려야 하는 것이다. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;‘AAB로 하니 더 좋은 걸?’이라고 느낄 만큼 구글이 많은 지원과 업데이트를 약속해주었으면 하는 바람이다. &lt;br /&gt;
개발자들이 개발하기 좋은 환경일수록 앱의 퀄리티도 올라갈 것이기 때문이다. &lt;br /&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 15 Nov 2021 10:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2021/11/15/apk_aab/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2021/11/15/apk_aab/</guid>
        
        <category>android</category>
        
        <category>apk</category>
        
        <category>aab</category>
        
        
      </item>
    
      <item>
        <title>Annotation 이해하기</title>
        <description>&lt;h2 id=&quot;들어가기-앞서&quot;&gt;들어가기 앞서&lt;/h2&gt;

&lt;p&gt;자바를 사용하며 봤었던 @Override 표시.
&lt;img src=&quot;/files/posts/20211111/override.png&quot; alt=&quot;override&quot; /&gt;&lt;/p&gt;

&lt;p&gt;단순히 “부모에 정의된 메소드를 오버라이딩했나보다.”  라며 넘어갔습니다.&lt;/p&gt;

&lt;p&gt;어노테이션을 잘 모르는채로 지냈는데, 어느 순간부터 점점 보이기 시작합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20211111/entity2.png&quot; alt=&quot;entity&quot; /&gt;
&lt;img src=&quot;/files/posts/20211111/getter.png&quot; alt=&quot;lombok&quot; /&gt;&lt;/p&gt;

&lt;p&gt;큰 의미 없었던 @기호 인줄 알았는데, 아니였습니다.&lt;/p&gt;

&lt;p&gt;@Getter, @Setter를 쓰면  알아서 아래 코드를 생성시켜주고
&lt;img src=&quot;/files/posts/20211111/getter2.png&quot; alt=&quot;lombok2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;@Column 한다음 name에 값을 넣어주면,   테이블 칼럼명에 적히게 됩니다.
&lt;img src=&quot;/files/posts/20211111/entity2.png&quot; alt=&quot;entity&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이쯤되니 아무 의미 없는 표시가 아님이 느껴졌고, 제대로 공부해봐야겠다는 생각이 들었습니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;annotation&quot;&gt;Annotation&lt;/h2&gt;

&lt;p&gt;oracle 사이트에는  어노테이션에 대해 아래처럼 적혀있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20211111/oracle_doc_annotation2.png&quot; alt=&quot;https://docs.oracle.com/javase/tutorial/java/annotations/&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이게 도대체 무슨 말이지..?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20211111/ohno.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;“프로그램에 대한 데이터를 제공한다”&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;컴파일러라는 프로그램에게  “@Override 적힌 메소드는 오버라이딩 목적으로 쓴거야. 만약 개발자가 메소드 이름을 잘못썼다면 알려줘. “&lt;br /&gt;
컴파일할때 @Getter, @Setter 들어간건 메소드 자동 생성해줘.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;이처럼 특정 기능들이 동작할 수 있게 만들어주는 것이 어노테이션 인거죠.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;FILED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;SOURCE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Getter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;어노테이션의 생김새는 이렇습니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;@Target은 어노테이션 기호를 어디에 붙일 수 있는지를 뜻하고,&lt;/li&gt;
  &lt;li&gt;@Retention은 어노테이션이 어느시점에 동작하는지를 뜻합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;예를 들어 위 Getter는 {ElementType.FILED, ElementType.TYPE} 이렇게 적혀있으니
필드영역에 적힐 수 있고,  클래스, 인터페이스 등에 적힐 수 있다는 뜻입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/posts/20211111/e_getter_2.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/files/posts/20211111/e_getter_1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(만약 Target에 적히지 않은 곳에 어노테이션을 쓰면 에러가 발생합니다.)&lt;/p&gt;

&lt;p&gt;그럼, 이런 어노테이션을 이용해서 무엇을 할 수 있을까요?&lt;/p&gt;

&lt;h2 id=&quot;어노테이션-활용&quot;&gt;어노테이션 활용&lt;/h2&gt;

&lt;p&gt;어노테이션은 비즈니스 로직에는 영향을 주지 않으면서, 특정 동작을 할 수 있게 만들어줍니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;METHOD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Rentention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AccessDeny&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;preHandle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HttpServletRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpServletResponse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;AccessDeny&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accessDeny&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAnnotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;AccessDeny&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accessDeny&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이런식으로 적으면, @AccessDeny 가 붙은 클래스나 메소드에 접근하는 요청이 들어왔을때 실행되지 않게 막을 수 있습니다.&lt;/p&gt;

&lt;p&gt;또한 spring에서 제공하는 handlerMethodArgumentsResolver를 이용하면 파라미터에 어노테이션을 적은것만으로 조금 더 깔끔하게 만들수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Controller&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TestController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;SessionUser&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;SessionUser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpSession&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;o&quot;&gt;~~&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Controller&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TestController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@LoginUser&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SessionUser&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;o&quot;&gt;~~&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PARAMETER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Rentention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RententionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LoginUser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LoginUserArgumentResolver&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HandlerMethodArgumentResolver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpSession&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpSession&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;supportsParameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MethodParameter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getParameterType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;equals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;LoginUser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;resolveArgument&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MethodParameter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ModelAndViewContainer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mavContainer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NativeWebRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebDataBinderFactory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;binderFactory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpSession&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(스프링 부트와 AWS로 혼자 구현하는 웹서비스 책 참고)&lt;/p&gt;

&lt;h2 id=&quot;마무리&quot;&gt;마무리&lt;/h2&gt;

&lt;p&gt;어노테이션을 처음 접했을땐 ‘이런 애가 있나보다’ 였는데,&lt;/p&gt;

&lt;p&gt;알아갈수록 활용만 잘하면 정말 매력적이게 사용할 수 있겠구나란 생각이 들었습니다.&lt;/p&gt;

&lt;p&gt;읽어주셔서 감사합니다.&lt;/p&gt;

</description>
        <pubDate>Wed, 10 Nov 2021 22:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2021/11/10/Annotation/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2021/11/10/Annotation/</guid>
        
        <category>annotation</category>
        
        
      </item>
    
      <item>
        <title>브라우저에서 비동기요청을 수행할 때 도움이 될 수도 있는 글 (api wrapping)</title>
        <description>&lt;h2 id=&quot;api-서버와의-통신&quot;&gt;API 서버와의 통신&lt;/h2&gt;

&lt;p&gt;웹 개발 환경이 여러모로 다양해지면서 REST API 서버를 별도로 두고 클라이언트(브라우저)에서 특정 endpoint를 호출해 CRUD를 수행하는 모델이 속속 등장하고 있습니다.&lt;/p&gt;

&lt;p&gt;이러한 개발을 진행하다 보면 자연스레 소위 AJAX(Asynchronous JavaScript and XML) 라고 불리우는 기법을 클라이언트단에서 활용하게 됩니다.&lt;/p&gt;

&lt;p&gt;AJAX 를 이용하기 위해서는 여러가지 방법이 있을 수 있는데, 먼저 js 네이티브단에서 지원하는 XMLHttpRequest (XHR이라고도 불리는)객체를 활용한 방법이 있겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;xmlhttprequest&quot;&gt;XMLHttpRequest&lt;/h2&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;XMLHttpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onreadystatechange&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 콜백은 간략화&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ok!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/someapi/foo/bar&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setRequestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위와 같이 직접 XMLHttpRequest 객체를 이용해 AJAX 기법을 이용해 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;그러나 직접 객체를 사용해 핸들링하는 방식은 여러모로 번거롭기도 하고, 가독성 측면에서도 떨어기 때문에 (콜백 함수 자체가 갖는 특성) 아마 이 방법 보다는 대부분 ajax를 jQuery에서 지원하는 내장함수를 이용해 접해 보았을 것으로 생각 됩니다.&lt;/p&gt;

&lt;h2 id=&quot;ajax&quot;&gt;$.ajax&lt;/h2&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ajax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/someapi/foo/bar&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;beforeSend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setRequestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ok!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 문단에서 XHR 객체를 직접 이용해 보냈던 요청과 동일한 요청을 jQuery 의 ajax함수를 이용해 보내 보았습니다.&lt;/p&gt;

&lt;p&gt;이렇게 2개를 함께 보니 $.ajax() 함수가 내부에서 어떤식으로 동작할지가 어느정도 머릿속에 그려지지 않나요?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;사실 엄밀히 말해서 jQuery는 내부적으로 XHR객체가 아닌 jqXHR 이라는 자체 모델을 이요하고 있긴 하지만 그 구성은 동일하게 이해할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;저는 처음 프로그래밍을 배울 때 $.ajax()를 습관적으로 이용 했기에 ajax통신 이라고 부르는 것이 $.ajax가 보통명사화 된 것으로 오해 했었는데요.&lt;/p&gt;

&lt;p&gt;ajax라는 것은 앞서 이야기 했던 통신 기법을 의미하는 명칭이며
$.ajax가 있고 나서 ajax 라는 기법이 있었던게 아니라&lt;/p&gt;

&lt;p&gt;AJAX 기법을 이용하기 쉽게 jQuery에서 제공해주는 함수 이름이 기법과 동일한 $.ajax() 였다는 것을 이제는 알게 되었습니다. (말이 좀 헷갈리긴 하네요)&lt;/p&gt;

&lt;h2 id=&quot;그-외의-ajax-통신을-돕는-것들&quot;&gt;그 외의 ajax 통신을 돕는 것들&lt;/h2&gt;

&lt;p&gt;정확히 언제 AJAX 라는 기법이 생겼는지에 대해서는 자세히 알기 어려우나,
현 시대에 와서는 너무나 당연한 기법이 되어버렸는데요&lt;/p&gt;

&lt;p&gt;그에 발맞추어 AJAX를 돕는 라이브러리나 native API단에서의 지원도 늘어 왔습니다.&lt;/p&gt;

&lt;p&gt;대표적으로 ECMA6와 함께 도입된 fetch API를 예로 들어볼 수 있겠네요.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promiseObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/someapi/foo/bar&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 코드에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;promiseObject&lt;/code&gt;에는 Promise 객체가 담겨 있을 것이고,&lt;/p&gt;

&lt;p&gt;then 체이닝을 통해 차근차근 XHR을 resolve해나갈 수 있도록 돕습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://bravenamme.github.io/2019/11/06/javascript-promise2/&quot;&gt;Promise에 대한 지난 포스트&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;또한 npm이 득세하면서 몇년 전부터 시장의 강자로 떠오르고 있는 &lt;a href=&quot;https://github.com/axios/axios&quot;&gt;axios&lt;/a&gt;를 예로 들어볼 수도 있습니다. (개인적으로 가장 선호하는 라이브러리 이기도 합니다.)&lt;/p&gt;

&lt;h2 id=&quot;wrapper가-있는게-좋을까&quot;&gt;wrapper가 있는게 좋을까?&lt;/h2&gt;

&lt;p&gt;이 외에도 여러 AJAX 라이브러리들이 생산 되고 있으며, 경우에 따라 유연하에 필요한 스펙에 맞춘 라이브러리를 도입하거나 fetch API와 같은 native api를 이용하는 경우도 있을 것입니다.&lt;/p&gt;

&lt;p&gt;그러나 우리가 모두 개발을 해 보아서 아시다시피 항상 요구사항은 바뀌기 마련이고 개발자는 그에 대해 유연하게 대처할 수 있는 준비를 해 둘 필요가 있었던 경험이 있으실 텐데요.&lt;/p&gt;

&lt;p&gt;같은 맥락으로 ajax 통신을 전담하는 라이브러리에 대한 교체가 필요한 시기가 도래했다고 할때, 소스코드 곳곳에서 $.ajax() 를 이용해 직접 이용 중이었다면 모든 소스를 찾아가며 수정이 필요하게 될 텐데요..&lt;/p&gt;

&lt;p&gt;이런 악몽같은 일을 미연에 방지하기 위해 제가 제안드리는 방법은 AJAX Request를 담당하는 추상화 계층을 하나 만들어 내부 구현체를 쉽게 변경할 수 있도록 하자는 것 입니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;마치 Hibernate로 내부가 구현된 레이어를 이용하지만 우리는 JPA(인터페이스)를 이용해 개발했다고 이야기 하는 것과 같은 느낌으로요&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;좀더 쉽게 이야기 하면 ajax 통신을 전담하는 모듈을 한번 감싸는 warpper 를 만들어 두는 것이라고 할 수 있겠네요.&lt;/p&gt;

&lt;p&gt;이 단순한 이야기를 하기 위해 서론이 정말정말 길었네요 ㅎ&lt;/p&gt;

&lt;h2 id=&quot;간단한-래퍼-예제&quot;&gt;간단한 래퍼 예제&lt;/h2&gt;

&lt;p&gt;다음으로는 제가 주로 이용하는 ajax 통신 wrapper 구조를 간단히 소개하고 마치고자 합니다.&lt;/p&gt;

&lt;p&gt;위 까지는 방법론적인 내용이었고, 실제 어떤 식으로 구현할지에 대해서는 사람에 따라 천차만별이며 해당 어플리케이션의 요구사항에 따라 스펙이 들쑥날쑥 할 수 있기 때문에 단순 참고용 으로만 봐 주세요&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// index.js&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// headers나 기타 공통 설정등이 필요하다면 이곳에서 한번에 세팅&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onNotFound&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 404일때 뭔가&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onServerError&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 500일때 뭔가&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onCatchProcess&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onNotFound&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onServerError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onCatchProcess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위와 같은 Promise를 리턴하는 래퍼로 한번 감싸서 ajax 라이브러리를 직접 사용하지 않고도 충분히 ajax콜이 가능하도록 이용한다면 에러핸들링이나 공통처리 등도 수월해지고, 관리포인트도 줄어드는 장점이 있다고 생각 합니다.&lt;/p&gt;
</description>
        <pubDate>Thu, 04 Nov 2021 10:00:00 +0900</pubDate>
        <link>https://bravenamme.github.io/2021/11/04/api-wrapper/</link>
        <guid isPermaLink="true">https://bravenamme.github.io/2021/11/04/api-wrapper/</guid>
        
        <category>javascript</category>
        
        
      </item>
    
  </channel>
</rss>
