<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>어쩌다, 블로그</title>
    <link>https://bkim.tistory.com/</link>
    <description>넓고 얕은 개발자</description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 14:04:22 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>김병규</managingEditor>
    <image>
      <title>어쩌다, 블로그</title>
      <url>https://t1.daumcdn.net/cfile/tistory/243FAB365638AF5802</url>
      <link>https://bkim.tistory.com</link>
    </image>
    <item>
      <title>[2편] 개발 7년차에서 매니저 3년차로(개발팀 7명에서 33명이 되기까지)</title>
      <link>https://bkim.tistory.com/28</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;들어가면서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://bkim.tistory.com/27&quot;&gt;[1편]&lt;/a&gt;에서 매니저로서 피해야 할 길(절망 편)에 대해서 이야기했다. 2편에서는 반대로 마주하고 나아가야 할 길(희망 편)에 대해서 말해보려 한다. 초보 매니저에게 도움이 되는 글이 되었으면 좋겠다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마주하고 나아가야 할 길&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;작은 목소리에 귀 기울이기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;emiliano-vittoriosi-PwXIsh7QpsI-unsplash.jpg&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;4288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dYnhJI/btrvJ9r40OY/InGrkhrO8qkxj2VPwjF1Wk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dYnhJI/btrvJ9r40OY/InGrkhrO8qkxj2VPwjF1Wk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dYnhJI/btrvJ9r40OY/InGrkhrO8qkxj2VPwjF1Wk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdYnhJI%2FbtrvJ9r40OY%2FInGrkhrO8qkxj2VPwjF1Wk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;626&quot; data-filename=&quot;emiliano-vittoriosi-PwXIsh7QpsI-unsplash.jpg&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;4288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 매니저가 된 이후 가장 어려웠던 부분은 구성원의 기분과 컨디션을 파악하는 일이었다. 팀원들에게 나의 의견을 강하게 전달하거나 회의에서 구성원과 반대되는 목소리를 내고 난 후에는 하루 종일 회의가 떠오르고 신경 쓰여 편히 쉴 수가 없었다. 구성원의 사기가 꺾이거나 실망하진 않았을지, 더 부드럽게 전달할 수 있는 방법은 없었는지 고민이 고민을 낳아 잠을 이루기 어려운 적도 많았다.(소심함이 문제였을지도...) 매니저로서 의사결정에 확신이 있었더라면 고민이 덜 했을지도 모르겠다. 하지만 나는 주니어 매니저였고 확신에 찬 결정을 할 수 있는 인사이트가 부족했다.&lt;br /&gt;&amp;nbsp; 이렇게 잠 못 드는 상황을 피하기 위해 구성원들에게 늘 반대 의견을 내어주길 요청했지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사실 구성원들이 강한 목소리를 내는 것은 매니저인 나보다 더욱 어려움이 따르는 일이었다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;그래서 나는 구성원에게 강한 목소리를 내어주는 것을 요구하는 것에 앞서 그들이 내어주고 있는 작은 목소리를 듣는 것에 집중했다. 주니어, 그리고 비전공자로서 가지는 고민, 회사 복지 체계에 대한 개선 의견, 장비나 의자와 같은 소모품에 대한 불편함 등 흘러가듯 오가는 말들에 집중하여 피드백을 드렸다. 모든 요청에 대하여 대하여 해결책을 드릴 수는 없었지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;작은 목소리에도 확실한 피드백을 드리는 것을 통해 구성원들의 의견 표현이 조금씩 늘어갔다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;작지만 분명한 피드백을 통해 활발한 의사소통을 이어간다면 프로덕트에 집중된 다양하고 강한 목소리도 편하게 낼 수 있지 않을까? 작은 목소리에 귀 기울이는것을 시작으로 구성원의 목소리에 집중하여 잠 못 드는 밤(서로의 상심을 걱정때문에)을 줄여가고 있다.&amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;동종 업계의 연봉 시세 확인하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 스타트업처럼 작은 회사는 HR을 위한 전문 부서를 꾸리기 어려울 때가 많다. HR부서가 없는 작은 조직의 경우 연봉협상을 위해 사내 연봉 테이블과 업무성과 평가표에 절대적으로 의존하기보다, 1차 조직장의 리뷰와 회사와 프로덕트의 성과를 바탕으로 연봉협상을 진행하는 경우가 많다.&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;우리 팀은 여기에 서라운드 리뷰라는 팀 평가기준을 더했지만 정량적인 기준이 되기엔 부족한 면이 있었다. 이런 상황에서 프로덕트의 성장을 위해 함께 달려온 동료와 돈 이야기를 나누고 연봉을 결정해야 하는 것은 초보 매니저에게 여간 어려운 일이 아니었다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(당장 나의 연봉 협상 자리도 어려운걸...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 더군다나&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;코로나 이슈로 인해 IT인력시장은 뜨겁게 달궈져 있었고 하루가 멀다 하고 &quot;OO기업 신입 연봉 6천만원!&quot;, &quot;이직 시 사이닝 보너스 1억 제공!&quot; 등 자극적인 채용가 홍보 쏟아지며 연봉협상의 난이도를 더욱 높였다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;konstantin-evdokimov-UUYkTnQkn9c-unsplash.jpg&quot; data-origin-width=&quot;4912&quot; data-origin-height=&quot;3264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cduCU6/btrvGazeqpk/JXTwGkiGhVtJG5mXn830kK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cduCU6/btrvGazeqpk/JXTwGkiGhVtJG5mXn830kK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cduCU6/btrvGazeqpk/JXTwGkiGhVtJG5mXn830kK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcduCU6%2FbtrvGazeqpk%2FJXTwGkiGhVtJG5mXn830kK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4912&quot; height=&quot;3264&quot; data-filename=&quot;konstantin-evdokimov-UUYkTnQkn9c-unsplash.jpg&quot; data-origin-width=&quot;4912&quot; data-origin-height=&quot;3264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp; 이런 상황에서 구성원의 이탈을 막고, 동기를 부여하면서도 회사까지 수용할 수 있는!! 회사와 구성원 사이에서 최대한의 협상 만족점을 찾아내야 한다는 고민에 빠졌다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나는 그 고민을 업계 시세에 기반하여 연봉을 협상하는 방법으로 덜어 낼 수 있었다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;헤드헌터로부터 우리 팀원이 제의받은 금액, 초봉 6천이라는 기업의 인재 요구 수준, 이직한 동료가 받는 연봉과 해당 회사의 연봉 밴드, 전 직장 동료들의 재계약 연봉 등 최대한 많은 곳에서 업계 싯가?를 모았고 이를 토대로 구성원과 회사 사이에서 합의점을 찾을 수 있었다.&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;어렵게 모은 업계 시세정보는 나와 구성원, 그리고 회사에게도 계약 연봉을 가늠할 수 있는 좋은 척도&lt;/b&gt;가 되었고 연봉 협상을 조금이나마 가볍게 시작할 수 있는 출발점으로 활용할 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;강약약약으로 처세하기 (강자에게 약하고, 약자에게도 약하게)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 회사의 정치적 구조를 생각하지 않고 프로덕트에 몰입할 수 있는 것은 스타트업이 가진 큰 매력점이다. 지나친 정치에서 벗어나기 위해 대기업에서 스타트업으로 이직하는 경우도 많다. 하지만 사람이 셋만 모이면 정치가 시작된다고 하지 않던가. 정도의 차이는 있겠지만, 성장하는 회사라면 구성원 간의 관계 복잡도 또한 올라가기 마련이다.&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;특히 매니저라는 직책은 협의를 통해 결과물을 만들어내는 것이 주요 업무이고, 정치적 구조안에서 풀어 가야 하는 일이 많기 때문에 매니저로서 협업을 위한 중심을 잡는 것이 중요하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나는 그 중심을 '정정당당함'에서 찾으려 했다&lt;/b&gt;. '강자에게는 강하고 약자에게는 귀를 귀울이는 것'을 정정당당한 것으로 생각했고 이에 맞춰 회사에서도 강강약약의 자세로 협업을 진행했다. 특히 강강에 집중했던 나는 상위 결정권자의 의견을 더욱 엄격한 기준으로 판단했고, 팀원들에게 부끄럽지 않은 결정을 해야 한다는 생각에 몰입했다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;하지만 '정정당당'함을 지키기 위한 노력이 협업에 도움이 되거나 프로덕트의 성장에 긍정적인 영향을 미쳤을까? 아니다. 매니저로서 2년이 지난 지금 돌이켜 보면, 나의 강강약약은 프로덕트와 팀원보다 나의 자존심을 더 잘 지켜내는 방법이었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 회사는 수익을 내기 위해 협업을 하는 곳이다. 강자에게 강하게 대응한다고 해서 우리의 프로덕트가 눈에 띄게 성장하거나, 우리 팀이 더 편해지지 않는다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;팀과 프로덕트의 성장을 위해서는 강자에게도 약하고 약자에게도 약한 자세를 취해서 최대한 많은 의견을 끌어내고 수렴해서, 발화자의 직책 높낮이에 상관없이 프로덕트만을 위한 결정을 해야 한다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;나보다 직책이 높은 사람의 의견을 따른다고 해서 아부하는 게 아니며, 직책이 낮은 사람의 의견을 반대한다고 해서 군림하는 것이 아님을 늦게 알게 되었다. (정말 집중하고 잘 보이기 위해 노력해야 하는 곳은 유저와 프로덕트였던 것을....) 그때부터 강약약약으로 대응하려 노력하고 있으나 잘 하고있는지 판단하기 위해서는 좀 더 시간이 필요할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;개밥 먹기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;photo-1433199675167-6a9774099cb3.jpg&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;1161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6jxhJ/btrvF9mOvMv/hkKSxlJBzrKLu1V97ekBzk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6jxhJ/btrvF9mOvMv/hkKSxlJBzrKLu1V97ekBzk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6jxhJ/btrvF9mOvMv/hkKSxlJBzrKLu1V97ekBzk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6jxhJ%2FbtrvF9mOvMv%2FhkKSxlJBzrKLu1V97ekBzk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;442&quot; height=&quot;292&quot; data-filename=&quot;photo-1433199675167-6a9774099cb3.jpg&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;1161&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;개밥 먹기란 우리가 개발하고 있는 프로덕트를 일상적인 생활과 업무에서 사용해보는 것을 뜻하는 IT업계 용어다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이스포츠 플랫폼을 개발하는 우리 팀의 경우 사내 게임대회를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lvup.gg&quot;&gt;레벨업지지&lt;/a&gt;에서 개최해 본다거나, 유저가 만든 대회에 직접 참가하는 것이 개밥을 먹는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;매니저에게 개밥 먹기는 우리가 만들고 있는 것이 무엇인지 제작자의 관점에서 한발 벗어나서 객관적으로 볼 수 있는 좋은 도구이다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;여러 곳에서 쏟아지는 아이디어를 정리하며, 기능을 구현하고 더하는 것에만 집중하다 보면 우리가 만들고 있는 것이 무엇인지 놓칠 때가 있다. 그럴 때면 개밥 먹기를 통해 우리 프로덕트의 현황을 파악하고 해결해야 할 문제점들을 파악할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 그리고 개밥 먹기는 애자일 형태로 개발을 진행하는 조직에게 필수사항으로 업무시간을 들여서라도 진행 하는 것을 추천한다. 무엇을 만들 것인지, 어떻게 만들 것인지, 이번 변경사항이 얼마나 의미있었는지, 어디를 개선해야 할지 등&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;애자일의 과정 과정마다 좋은 아이디어를 낼 수 있는 원동력을 프로덕트에 대한 이해도로부터 얻을 수 있기&lt;/b&gt;&amp;nbsp;&lt;b&gt;때문&lt;/b&gt;이다. 기획자와 디자이너는 물론 개발자와 운영자까지 유저로서 프로덕트를 이해한다면 각자의 파트에서 더욱 의미 있는 역할을 해낼 수 있을 것이라 믿는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;투명한 정보 공유&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;매니저 업무를 시작하면서 관리해야 하는 정보의 양이 기존보다 두배 이상 증가했다. 실무자일 때보다 더 많은 회의에 참석했고, 더 많은 의사 결정에 참여함으로써 운영진과 타 부서의 정보도 챙겨야 했다&lt;/b&gt;. 매니저로서 얻는 정보를 어디까지 구성원에게 공유해야 할까?라는 물음표가 생겼고, 잦은 결정 변경으로 인한 피로감, 무뎌짐, 실패의식을 느꼈던 과거 실무자로서의 경험을 바탕으로 '확정된 것만 공유하자'라는 판단을 했었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 하지만 대표님은 반대로 대부분의 정보(심지어 투자 현황까지)를 전 직원에 공유했고, 나의 우려와는 반대로, 정보를 받아들이는 주체였던 구성원들은 성숙하게 정보를 소화해내고 있었다.&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;빅픽처의 동료들은 나보다 훨씬 더 강하고 성숙한 사람들이었고, 모든 정보를 투명하게 공유하였을 때 실망하거나 걱정하기에 앞서 그들의 사유를 바탕으로 판단하고 있었다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;정보의 제한을 통해 피할 수 있었던 실망과 아쉬움을 감내해야하는 경우도 있었지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;투명한 정보 공유로부터 오는 고통은 정보를 차단하고 필터링 하는 것으로부터 오는 부작용보다 건강하고 성장의 바탕이 되는 성장통이었다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;앞선 경험을 통해 나 역시 확정된 정보만 공유하는 것에서 모든 정보를 투명하게 공유하는 것으로 자세를 바꾸었다. 정보를 투명하게 공유함으로써 쌓이는 신뢰도는 우리를 더 단단하게 만들어 주었고 정보 공유를 더 편하게 할 수 있는 선순환구조가 자연스럽게 생겨나 매니저로서 정보를 관리해야 하는 어려움을 줄일 수 있었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마치면서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://bkim.tistory.com/27&quot;&gt;[1편]&lt;/a&gt;은 하면 안 되는 것들에 대하여 적다 보니 편하게 쓸 수 있었나보다. 이번 편은 해야 하는 것들에 대해 적다 보니 소심함과 조심스러움이 더해져 문장들마다 쉼표가 늘어났다. 이제 막 3년 차에 접어드는 초보 매니저의 글로써 나와 비슷한 길에 올라선 분들께 조금이나마 도움이 되는 글이길 바란다. 다음 회고 때는 조금 더 자신감을 뿜뿜할 수 있기를....!&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;squar.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;776&quot;&gt;&lt;a href=&quot;https://blog.bigpi.co/65&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnYdBX/btrvGbkypBH/9T0dm7JkKX4zp9Cecc1Uq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnYdBX%2FbtrvGbkypBH%2F9T0dm7JkKX4zp9Cecc1Uq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;83&quot; height=&quot;83&quot; data-filename=&quot;squar.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;김병규 &lt;/b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;bk@bigpi.co)&lt;/span&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;새로움과 자유로움을 좋아하는 개발자입니다.&lt;br /&gt;프로덕트의 성장은 구성원의 성장으로부터 온다고 믿습니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <category>STARTUP</category>
      <category>개발자</category>
      <category>개발팀만들기</category>
      <category>매니저</category>
      <category>스타트업</category>
      <category>조직성장</category>
      <category>팀성장</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/28</guid>
      <comments>https://bkim.tistory.com/28#entry28comment</comments>
      <pubDate>Fri, 11 Mar 2022 16:37:23 +0900</pubDate>
    </item>
    <item>
      <title>[1편] 개발 7년차에서 매니저 3년차로(개발팀 7명에서 33명이 되기까지)</title>
      <link>https://bkim.tistory.com/27</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;들어가면서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 실무자가 매니저로 넘어가는 길에 도움이 되는 이정표를 작게나마 더하고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;개발자로 7년을 일하다 7명을 팀원을 맡게 되고(&lt;a href=&quot;https://blog.bigpi.co/65&quot;&gt;자기소개의 글&lt;/a&gt;), 2년간 팀과 함께 성장하며 33명이 되기까지 경험을 바탕으로 피해서 돌아가야 할 것과 마주하고 정면 돌파해야 하는 것들을 정리해 보았다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;피하고 돌아가야 할 길&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;kees-streefkerk-TrqQBU3xMEs-unsplash.jpg&quot; data-origin-width=&quot;2852&quot; data-origin-height=&quot;3809&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cni0mb/btrvJSREcVd/RScxmmk3NT9u9kfQwzUk1k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cni0mb/btrvJSREcVd/RScxmmk3NT9u9kfQwzUk1k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cni0mb/btrvJSREcVd/RScxmmk3NT9u9kfQwzUk1k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcni0mb%2FbtrvJSREcVd%2FRScxmmk3NT9u9kfQwzUk1k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;445&quot; height=&quot;3809&quot; data-filename=&quot;kees-streefkerk-TrqQBU3xMEs-unsplash.jpg&quot; data-origin-width=&quot;2852&quot; data-origin-height=&quot;3809&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;비교형 문장&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 우리 팀은 반기마다 서라운드 리뷰(협업했던 동료를 서로 리뷰하고 평가함)를 진행한다. 팀을 리드하는 입장에서 좀처럼 받기 어려운 동료들의 피드백을 들을 수 있는 소중한 시간이다. 서라운드 리뷰를 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나는 &quot;프런트엔드와 백엔드를 비교하며 표현하지 말아 달라.&quot;라는 피드백을 받았다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;할 일을 계획하는 부서회의 때 &quot;A라는 기능은 트랜잭션 관리 때문에 프런트엔드 개발보다 백엔드 개발이 중요하다. 일정을 더 많이 잡아 달라&quot;라는 표현을 하였고 이에 대한 피드백으로 주신 말씀이었다. 너무나 맞는 피드백이었고 늘 새기며 일하게 되었다. 업무량과 영향범위는 다를 수 있지만&amp;nbsp; 무엇이 더 중요한 일은 없다. 더 중요하다고 생각되더라도 그것은 개인의 의견일 뿐 모두가 동의할 수 있는 사실은 아니다.&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp; 비교하는 표현을 사용하면 부정적으로 표현되는 면이 생기기 마련이다. 매니저가 전체회의에서 하는 말은 영향력이 크기 때문에 비교형 문장은 피하자.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;개발 리소스에 등 떠밀리기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 스타트업은 언제나 리소스가 부족하다. FE개발자에게 퍼블리싱 작업은 기본이고 데이터 지표 추적 같은 스크립트 추가는 일상이다. 이런 상황에서 새로운 프로젝트를 목표한 기간 안에 완성하기 위해 가장 쉽게 선택할 수 있는 선택지는 개발자 채용이다. (채용 난이도도 높지만 개발자 출신 뉴비 매니저였던 나는 '그 일정으로는 안됩니다'라고 말하고 실망감을 감내하는 것보다 채용을 통해 일정을 맞추는 방향이 좀 더 쉬웠다.)&lt;br /&gt;&amp;nbsp; 어려운 채용시장에 맞춰 주니어 역량의 구성원을 채용하고 성장을 유도하며 프로젝트를 완료한 뒤 우리 팀은 디자인/기획 리소스에 비해 개발 리소스가 큰 조직이 되었다.(팀 유지비용이 올라가는 것은 덤이었다.)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이때부터 매니저로서의 나는 '개발자를 놀릴 순 없어!', '개발하지 않으면 재미가 없어져버린다구!'라는 생각을 하며 충분한 고민이 담기지 않은 기획서와 디자인을 요구했고, 유기적으로 돌아가는 팀을 보며 흐뭇해하기까지 했다. 높아진 팀 유지비용을 성과로서 상쇄해야 한다는 조바심이 더해져 상황은 좀처럼 나아질 기미가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;조바심이 난 매니저는 어떤 행동이든 할 수 있는 무서운 동물이었다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;의욕이 넘치는 초보 매니저로서 회사를 위해 열심히 달리고 목표를 완수하기 위해 최선을 다했을 뿐인데 나는 예측 불가한 추진체가 되어 있었다. 자연스럽게도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;개발 리소스에 등이 떠밀리게 되었고 매니저로서 부족한 결정을 하면서 팀과 프로덕트의 성장에 걸림돌을 만들었다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 사용자를 충분히 고려하지 않거나 모두를 만족시키기 위해 복잡한 기능을 설계하고, 유지보수에 사용되는 리소스 예측에 소홀해 매일같이 야근이 이어졌다. 무엇보다 철야하며 구현한 기능들이 유저에게 외면받을 때에는 그 원인을 나에게서 찾지 않고 시장을 탓하곤 했다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자연스럽고 쉽게 빠져들 수 있는 실수로 인한 등떠밀림의 효과는 강력했고, 그로 인한 결과는 랜덤박스처럼 다방면에서 터져 나왔다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;매니저는 여유롭게 고민하는 시간이 많아야 한다는 조언을 들었을 때 이것은 무슨 소리인가! 했었는데 실수를 거듭하고 난 뒤에야 비싼 값을 치르고 그 의미를 체득하게 되었다. 다시 처음으로 돌아갈 수 있다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;개발 리소스를 늘리기 전에 충분히 고민하고 설계할 수 있는 기획/디자인 리소스 그리고 개발 리소스를 효율적으로 사용할 수 있는 매니저로서의 역량을 먼저 준비할 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;매니징과 실무를 동시에 하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 개발자에서 초보 매니저로 넘어온 나는 의욕이 넘쳤다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;동료들에게 기술역량이 있는 매니저로서 인정받고 싶었고 코드를 작성하는 실무를 통해 증명할 수 있다고 생각했다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하지만 실무를 통해 구성원의 신뢰를 얻을 수 있었던 기간은 고작 6개월이었던 것 같다. 성장곡선이 너무나 가팔랐던 동료들은 내가 공유했던 기술 레벨 수준을 각자의 분야에서 빠르게 뛰어넘었고 나는 그들이 챙기지 못하거나 리소스 부족으로 담당자가 없는 업무들을 찾아 빈틈을 채우는 정도로 실무를 이어갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 물론 실무를 이어가며 매니징을 하는데 문제가 없다면 실무에도 도움이 되는 매니저가 될 수 있었다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;하지만 나는 초보 매니저였고, 새로운 업무에 적응하기 위해 모든 리소스를 사용하여도 부족한 상황인 것이 문제였다. 그로 인해 매니저로서 해야 하는 것들을 놓치는 경우가 많았고, 실무에도 온전히 집중할 수 없어 리팩터링이 필요한 코드들이 쌓여갔다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 매니징과 실무를 동시에 하느라 매일같이 야근하는 매니저, 거기에다 완성도 낮은 코드와 인사이트가 부족한 결정을 내리는 리더와 함께 일하는 동료들은 얼마나 힘이 들지 그때는 미처 생각하지 못했다. 초보 매니저라면 겸업은 피하고 매니저로서의 역할을 먼저 소화해 내는 것이 동료들에게 깊은 신뢰를 얻을 수 있는 길이 아니었을까. 역시나 다시 돌아간다면 매니저로서 역할을 할 수 있도록 온전히 노력을 쏟고 싶다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;time-g7b8ab065e_1920.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch3ehj/btrvJUonEci/fKLxIPPXVOzJJ1zLaWiHkK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch3ehj/btrvJUonEci/fKLxIPPXVOzJJ1zLaWiHkK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch3ehj/btrvJUonEci/fKLxIPPXVOzJJ1zLaWiHkK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch3ehj%2FbtrvJUonEci%2FfKLxIPPXVOzJJ1zLaWiHkK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;551&quot; height=&quot;367&quot; data-filename=&quot;time-g7b8ab065e_1920.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;K-애자일&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스타트업이나 소프트웨어를 개발하는 IT조직에서는 애자일 방법론을 채택하는 경우가 많다.&lt;br /&gt;K-애자일을 논하기 전에 찐&amp;nbsp;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;http://agilemanifesto.org/iso/ko/manifesto.html&quot;&gt;애자일 선언문&lt;/a&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;먼저 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;공정과 도구보다&amp;nbsp;개인과 상호작용을, 포괄적인 문서보다&amp;nbsp;작동하는 소프트웨어를&lt;br /&gt;계약 협상보다&amp;nbsp;고객과의 협력을, 계획을 따르기보다&amp;nbsp;변화에 대응하기를 가치 있게 여긴다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;content_lean_kniberg-600x417.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;417&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ltjDY/btrvH0CQFec/cGELXlSMApFbHKtMn3D7Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ltjDY/btrvH0CQFec/cGELXlSMApFbHKtMn3D7Jk/img.png&quot; data-alt=&quot;Source: YouTube, Making Sense of MVP (Minimum Viable Product), https://youtu.be/0P7nCmln7PM&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ltjDY/btrvH0CQFec/cGELXlSMApFbHKtMn3D7Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FltjDY%2FbtrvH0CQFec%2FcGELXlSMApFbHKtMn3D7Jk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;417&quot; data-filename=&quot;content_lean_kniberg-600x417.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;417&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Source: YouTube, Making Sense of MVP (Minimum Viable Product), https://youtu.be/0P7nCmln7PM&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 나는 애자일 선언문을 바탕으로 최소 기능 제품(MVP)을 만드는데 주력하고 유저에 집중하여 완성도를 높여가는(때로는 목적지도 바꾸어가며) 형태로 일하려고 했다(근데 못했다). 지난 2년간 우리 팀은 정말 유저에 집중하고 있었을까? 프로덕트의 완성도를 높여가는데 집중하고 있었을까? 반문해보면 명확히 '아니다'라는 답이 돌아온다. 그러면 내가 추구하고 요구했던 개발 방법론은 무엇이었을까? 그것은 바로 K-애자일이었다 흑ㅠ흑ㅠ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;527&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HQHDn/btrvGXNayLT/msLE1ZHdPKVkXQxacfV1cK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HQHDn/btrvGXNayLT/msLE1ZHdPKVkXQxacfV1cK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HQHDn/btrvGXNayLT/msLE1ZHdPKVkXQxacfV1cK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHQHDn%2FbtrvGXNayLT%2FmsLE1ZHdPKVkXQxacfV1cK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;850&quot; height=&quot;527&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;527&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우리가 했던 K-애자일은 이렇게 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;① 스프린트 결과에 대한 정량적, 정성적 성과를 측정할 수 있는 환경이 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 이전 스프린트의 성과를 측정하지 않고서 다음 스프린트를 계획할 수 있을까? 스케이트보드가 제대로 완성되었는지 알기 어려운 상황에서 핸들을 추가한다면 그것은 킥보드로서 동작할 수 있을 것인가? 거듭되는 스프린트마다 행운이 따라야만 우리는 목적지에 다다를 수 있을 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;② 결과물(목적지)은 변경할 수 없으며, 개발 완료 시점이 확정되어있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 나는 스프린트로 작업해나가는 것을 관철했고 스프린트를 계획하고 종료하는 기준은 배포일이었다. 2주 또는 3주마다 배포일을 지정해두고 배포일에 맞춰 스프린트를 진행했다. 정해진 개발 완료 시점으로 인해 우리 팀은 유저와 기능에 대하여 충분히 고민할 시간은 줄어들고 기획 파트와 개발 파트의 갈등을 야기했다. 기획서 리뷰 시간에 개발자 의견이 더해지면 기획자는 다시 기획서를 업데이트해야 했고, 그만큼 개발할 시간은 줄어들기에 일정을 더 확보해야 했다. (그러나 일정을 추가하지 못하는 것이 K-애자일의 핵심!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;③ 기능 배포 시점을 팀 외부(타 부서, 고객사 등)에서 결정한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 앞선 ②번의 상황에서 기능의 퀄리티 높이기 위해서는 일정을 조율하고 다시 첫 스탭부터 수정해나가는 과정을 반복해야 한다. 하지만 기능 배포 시점을 우리가 조정할 수 있는 상황이 아니라면? 스프린트를 진행하는 중간에 꼭 개발해야만 하는 기능이 추가된다면? 무엇보다 그것이 전사 관점의 이슈(이것은 몹시 민감하고 예민하다.)가 반영되어있다면, 개발팀은 일정보다 늦게 완성된 기획서에 발맞춰 개발을 해내야만 한다. 이를 통해 우리는 파트 간 볼맨 소리, 퀄리티의 결핍, 우리가 원했던 건 이게 아닌 데와 같은 다양한 부작용을 얻게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;④ ①번부터 ③번까지 과정을 반복한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 어쩌면 워터폴 방식이 어울렸을 우리 조직에 K-애자일이 자리 잡게 된 것은 애자일에 대한 이해도가 부족한 상태에서 애자일을 해야 한다고 큰소리로 주장했던 매니저(나)가 가장 큰 원인이었다. &quot;한국 기업들에서 행해지는 애자일 방법론은 일을 빠르게 많이 시키기 위한 것이 아니냐&quot;는 글이 커뮤니티에 올라올 때마다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&quot;&lt;/span&gt;&lt;s&gt;우리는 아니야&lt;/s&gt;(응 맞아)&quot;라며 현실을 부정하는 내 모습이 늘 함께했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 다행히도 우리 조직은 얼마 전 애자일을 코치와 스크럼 마스터를 전담해주시는 @김영민 님을 만나게 되어 건강한 애자일 문화를 처음부터 다시 키워나가고 나가고 있다. 곧 건강한 애자일 문화에 대한 블로그를 올릴 수 있을 것 같아, 자조 섞인 K-애자일에 대한 설명은 서둘러 마친다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;product-owner-e1567519253529.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhvGNE/btrvJUonEwh/6MLseVUgxjT7khYszLcj00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhvGNE/btrvJUonEwh/6MLseVUgxjT7khYszLcj00/img.png&quot; data-alt=&quot;Source: YouTube Product Owner in a Nutshell, https://youtu.be/502ILHjX9EE&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhvGNE/btrvJUonEwh/6MLseVUgxjT7khYszLcj00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhvGNE%2FbtrvJUonEwh%2F6MLseVUgxjT7khYszLcj00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;450&quot; data-filename=&quot;product-owner-e1567519253529.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Source: YouTube Product Owner in a Nutshell, https://youtu.be/502ILHjX9EE&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마치면서&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 초보 매니저로서 피하고 돌아가야 할 길을 작성하다 보니, 내용이 너무 길어져 버렸다. 아마도 많은 길을 돌아왔기 때문이 아닐까? 매니저로서 역할을 더 잘했다면 피해 갈 수 있었던 길들을 돌아보면서, 어떤 문제든 팀에서 발생하는 문제는 모두 매니저의 책임임을 또 한 번 느낀다.  (그렇다면 잘한 것도 모두!?  )&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 피해 가야 할 길에 대해서 글을 쓰다 보니 반성문이 되어버렸다. 잘해온 것도 무척?이나 많기에, 반대로 마주하고 지나가야 할 길에 대해서 페이지를 분리해서 공유할 예정이다. 내가 작성한 글이 나와 비슷한 길에 올라서 있는 분들께 조금이나마 도움이 되고 실수를 덜할 수 있는, 혹은 잘못된 길은 피해 갈 수 있는 단서가 될 수 있으면 좋겠다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://bkim.tistory.com/28&quot;&gt;다음 글) 마주하고 지나가야 할 길&amp;nbsp;&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&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;li&gt;투명한 정보 공유&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;squar.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;776&quot;&gt;&lt;a href=&quot;https://blog.bigpi.co/65&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mAJdl/btrvJUu8Gsz/FuJZKGdz5TBjHWV9Nukf5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmAJdl%2FbtrvJUu8Gsz%2FFuJZKGdz5TBjHWV9Nukf5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;83&quot; height=&quot;83&quot; data-filename=&quot;squar.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;김병규 &lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;bk@bigpi.co)&lt;/span&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;새로움과 자유로움을 좋아하는 개발자입니다.&lt;br /&gt;프로덕트의 성장은 구성원의 성장으로부터 온다고 믿습니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <category>STARTUP</category>
      <category>K애자일</category>
      <category>PM</category>
      <category>개발자</category>
      <category>개발팀</category>
      <category>매니저</category>
      <category>스타트업</category>
      <category>실무자</category>
      <category>조직성장</category>
      <category>팀성장</category>
      <category>회고</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/27</guid>
      <comments>https://bkim.tistory.com/27#entry27comment</comments>
      <pubDate>Fri, 11 Mar 2022 16:35:35 +0900</pubDate>
    </item>
    <item>
      <title>[애자일로 빅픽처를 그리다] 데이터 대시보드 #2</title>
      <link>https://bkim.tistory.com/26</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;들어가면서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 지난&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://bkim.tistory.com/25&quot;&gt;데이터 대시보드 1편&lt;/a&gt;에서 공유한 데이터 대시보드를 고도화하고 당시 아쉬웠던 부분들(고객군 분리, 유저 획득 경로 상세화, 리소스 데이터 추가)을 보완한 내용을 공유한다. 데이터 대시보드 생성 이후 프로덕트를 담당하는 팀원들의&amp;nbsp; 아이디어가 더해지면서 조금 더 실용적인 지표들이 추가되었다. 정답이 없는 질문에 최선의 답을 구하기 위해, 계속해서 데이터와 결과물을 조정해야 하는 작업이다 보니 소심해지고 , 집단지성 에 기대게 된다. 이 글도 집단지성이라는 호수에 한 방울  보탬이 되기를, 그리고 다음 단계를 제안하고 발전할 수 있는 발판이 될 수 있기를 바란다. &lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;대시보드 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 기존에 구축했던 데이터 대시보드에는 프로덕트 사용자의 흐름을 전반적으로 살펴보는 AARRR 분석만 존재했다. 동료들에게 AARRR 대시보드를 공유하고 나서, 프로덕트 담당자들이 가지고 있는 개발 스토리에 대한 기능별 대시보드 생성 요청을 받았고 이에 맞춰 3가지 대시보드를 추가했다. 새로운 대시보드를 추가하면서 데이터 구렁텅이에서 방향감각을 잃어 갈 때마다 아래 세 가지 포인트를 기준점으로 다시 정신을 부여잡고 작업을 진행했다. 새롭게 추가한 대시보드들을 소개하며 더불어 대시보드를 통해 개인적으로 얻을 수 있었던 힌트들을 첨언했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt; 우리가&amp;nbsp;&lt;/span&gt;무엇을 위해 리소스를 투입하는지 목표에 대한 선명도를 높이자.(목표)&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt; &lt;/span&gt;유저에게 전달한 스토리는 목표를 달성했는지 확인할 수 있어야 한다.(결과 측정)&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt; &lt;/span&gt;다음 작업에서 우리가 집중해야 할 부분은 무엇인지 힌트를 제공하자.(계획)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유저 랜딩 기능분석&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(연관 페이지 :&amp;nbsp;&lt;a href=&quot;https://online.gamecoach.pro/&quot;&gt;online.gamecoach.pro&lt;/a&gt;)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목표
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신규 수강생 방문자에게 제품의 핵심 가치를 전달한다.&lt;/li&gt;
&lt;li&gt;방문자가 CTA버튼 통해 핵심 Task를 수행하도록 유도한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;결과 측정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신규 수강생 페이지 참여도 지표 (참여율, 평균 참여 시간, 스크롤 90%, 기타 세부 이벤트)&lt;/li&gt;
&lt;li&gt;CTA버튼 클릭률 (CTA 클릭 수 / 첫 방문자 수,&amp;nbsp; CTA 클릭 수 / 세션 수, CTA 클릭 수 / 페이지 방문 수)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;특이사항 &amp;amp; 힌트&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CTA버튼 클릭률을 어떤 기준으로 보아야 할 것인지에 대한 고민이 필요하다. 첫 방문자의 CTA 클릭률이 유저 랜딩 페이지의 목적에 가장 적합하고 퍼센트도 가장 높은 상황이지만, 목표한 클릭률을 달성했는지 등의 성공 판단 기준이 추가된다면 다음 단계를 고민하는데 더욱 도움 될 것으로 보인다.&lt;/li&gt;
&lt;li&gt;기존 유저의 CTA 버튼 클릭률은 첫 방문자 대비하여 12 ~ 20% 낮은 상황이다. 재방문자에게는 상대적으로 CTA 버튼이 매력적으로 다가가지 못하고 있다. 재방문에게 맞는 CTA버튼이나 기능 등 리텐션과 연계해서 고민해 본다며 개선 목표를 정할 수 있을 것 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2Ucwo/btrvJxUj5yu/QQiv7MpZ9io3RTNTE3MkS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2Ucwo/btrvJxUj5yu/QQiv7MpZ9io3RTNTE3MkS0/img.png&quot; data-alt=&quot;CTA 클릭률 지표를 메인으로하는 유저 랜딩 대시보드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2Ucwo/btrvJxUj5yu/QQiv7MpZ9io3RTNTE3MkS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2Ucwo%2FbtrvJxUj5yu%2FQQiv7MpZ9io3RTNTE3MkS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1468&quot; height=&quot;576&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CTA 클릭률 지표를 메인으로하는 유저 랜딩 대시보드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;코치 추천 기능분석&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(연관 페이지 :&amp;nbsp;&lt;a href=&quot;https://online.gamecoach.pro/coach-matching&quot;&gt;online.gamecoach.pro/coach-matching&lt;/a&gt;)&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목표
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신규 방문자와 코치님의 1:1 채팅 성사율을 높인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;결과 측정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생애 첫 채팅과 일반 채팅 성사에 대한 커스텀 이벤트를 생성하여 분자에 대입하고 첫 발문자 수, 세션 시작 수를 분모로 활용하여 목표 결과를 측정할 수 있는 3가지 핵심 지표를 등록했다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;추천 코치 페이지에서 추천받기 시작부터 추천받기 완료, 추천 코치 카드 선택 등 스탭 별 참여도 지표를 생성하여 유저가 코치를 추천받는 스탭 별 정보를 시각화했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;특이사항 &amp;amp; 힌트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커스텀 이벤트를 만드는 과정에서 이벤트 등록을 누락한 포인트가 있어서 중요 포인트인 `채팅 수` 값이 상당기간 오염되어 있었다. 확인 즉시 수정하였지만 과거 데이터와 비교가 불가하여 아쉬운 점이 있었다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;추천받기 완료율 | 채팅 성사율 | 수강 결제 완료율&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;세 가지 지표 간에 강한 연관도가 있을 것으로 보인다. 수강률은 프로덕트 최종 목표에 직결되는 분명한 지표지만 수강률 상승까지 복잡한 단계와 설계가 필요하다. 반면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;채팅 성사율 | 추천받기&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;완료율&lt;/b&gt;은 접근 단계가 단순하고, 수강률과 강한 연관이 있기 때문에 수강률 상승을 위한 분할 공략지점으로 활용할 수 있을 것으로 보인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1BK9j/btrvFBju8Dg/mfGFj0bkjPvuonek35xn01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1BK9j/btrvFBju8Dg/mfGFj0bkjPvuonek35xn01/img.png&quot; data-alt=&quot;수강생과 코치의 채팅 성사율을 메인으로하는 추천 코치 대시보드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1BK9j/btrvFBju8Dg/mfGFj0bkjPvuonek35xn01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1BK9j%2FbtrvFBju8Dg%2FmfGFj0bkjPvuonek35xn01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1488&quot; height=&quot;608&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수강생과 코치의 채팅 성사율을 메인으로하는 추천 코치 대시보드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;코치 찾기 기능분석&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(연관 페이지 :&amp;nbsp;&lt;a href=&quot;https://online.gamecoach.pro/coach-finder&quot;&gt;online.gamecoach.pro/coach-finder&lt;/a&gt;)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목표
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수강생이 코치를 검색하는 행동을 분석한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;결과 측정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수강생이 어떤 코치를 찾는지, 중요하게 보는 이력은 무엇인지 등 유저의 니즈를 파악하는 것은 유저 페르소나를 선정할 때 매우 중요한 부분이다. 코치 찾기 페이지를 오픈 한 뒤 실제 유저가 검색하는 태그와 정렬 등 클릭 위주의 데이터를 수집하여 시각화했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;특이사항 &amp;amp; 힌트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코치를 검색하기 위해 태그를 클릭하거나 우선순위 정렬을 변경하는 등의 액션이 페이지 뷰 대비 10% 이하로 측정되었다. 코치를 검색하고 정렬하는 기능 자체의 사용률이 낮은 것을 바탕으로 수강생이 코치를 검색하기 이전에 검색이 필요한 환경을 마련하는 것이 우선일지 고민해봐야겠다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1259&quot; data-origin-height=&quot;423&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOKDUT/btrvEKNVVGo/GgLLbk6izL6cAnQQSkZTwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOKDUT/btrvEKNVVGo/GgLLbk6izL6cAnQQSkZTwK/img.png&quot; data-alt=&quot;코치 찾기에서 유저들이 사용하는 정렬기준 정보들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOKDUT/btrvEKNVVGo/GgLLbk6izL6cAnQQSkZTwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOKDUT%2FbtrvEKNVVGo%2FGgLLbk6izL6cAnQQSkZTwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1259&quot; height=&quot;423&quot; data-origin-width=&quot;1259&quot; data-origin-height=&quot;423&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코치 찾기에서 유저들이 사용하는 정렬기준 정보들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;고객군 분리 &amp;amp; 유저 획득 경로 상세화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 대시보드 개선을 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;유저 타입을 세분화하여 데이터를 필터링할 수 있는 뷰&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;유저 획득 경로를 상세화하여 주요 유입 포인트를 필터링할 수 있는 뷰&lt;/b&gt;를 제공하려 노력했다. 무엇보다 기능 안정화 이후 본격적인 마케팅을 진행할 예정이어서,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;신규 유저의 획득 경로 파악이 꼭 필요한 상황이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp; 먼저 유저 타입을 세분화하기 위해 GA4 연동 스크립트에 userId와 user_properties값을 추가하여 로그인 여부 및 유저 역할(수강생, 코치)을 GA4 보고서의 비교 기준으로 사용할 수 있도록 개선했다. 작업량은 크지 않았은데 레퍼런스가 적고 공유된 자료들은 쇼핑몰 기준이라&amp;nbsp;&lt;a href=&quot;https://online.gamecoach.pro/&quot;&gt;온라인 게임코치 서비스&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;특성에 맞게 커스텀하기에 어려움이 있었다. (결과적으로 GA4 연동 스크립트를 수정하여 대부분 gtag의 'config'기능을 사용하여 세팅했다. 비슷한 작업을 하실 분들을 위해&amp;nbsp;&lt;a href=&quot;https://developers.google.com/analytics/devguides/collection/ga4/reference/config&quot;&gt;구글 공식문서&lt;/a&gt;를 추천한다.) userId와 user_properties값을 세팅한 이후에는 데이터 비교/필터링 기준으로 로그인 여부와 유저 타입 (코치인지, 학생인지)을 선택할 수 있게 되었고 코치와 유저라는 양 극단에 위치한 유저들의 데이터를 분리하여 확인/비교할 수 있게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1513&quot; data-origin-height=&quot;753&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baadwl/btrvE40xNaF/DBW20f9WH3bktFFIqTiAC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baadwl/btrvE40xNaF/DBW20f9WH3bktFFIqTiAC0/img.png&quot; data-alt=&quot;[개발환경 테스트 지표] 로그인 여부와 user_role을 기준으로 실시간 지표를 비교 할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baadwl/btrvE40xNaF/DBW20f9WH3bktFFIqTiAC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbaadwl%2FbtrvE40xNaF%2FDBW20f9WH3bktFFIqTiAC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1513&quot; height=&quot;753&quot; data-origin-width=&quot;1513&quot; data-origin-height=&quot;753&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[개발환경 테스트 지표] 로그인 여부와 user_role을 기준으로 실시간 지표를 비교 할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 두 번째로 유저 획득 경로를 상세화 하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://ga-dev-tools.web.app/ga4/campaign-url-builder/&quot;&gt;구글 캠페인 URL 빌더&lt;/a&gt;를 적극 활용했다. 구글&amp;nbsp; 캠페인 URL 규격에 맞춰 생성한 URL을 통해 유저가 페이지를 방문하면 URL에 세팅한 referrer(source)와 medium, campaign name 등의 데이터를 얻을 수 있다. 이 기능을 이용하여 direct와 not set으로 뭉쳐져 있던 세션 유입 경로를 각 캠페인, 소스 등으로 세분화하여 확인할 수 있게 되었다. (드디어 direct와 not set의 유입 순위를 떨어뜨렸다.  )&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;875&quot; data-origin-height=&quot;487&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m89o6/btrvEJ2vqm3/Ypbq2arUxye2w9BM1pubWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m89o6/btrvEJ2vqm3/Ypbq2arUxye2w9BM1pubWk/img.png&quot; data-alt=&quot;획득한 트래픽 차트에서 기존에 최상위었던 referral, direct, not set이 하위로 내려간 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m89o6/btrvEJ2vqm3/Ypbq2arUxye2w9BM1pubWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm89o6%2FbtrvEJ2vqm3%2FYpbq2arUxye2w9BM1pubWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;875&quot; height=&quot;487&quot; data-origin-width=&quot;875&quot; data-origin-height=&quot;487&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;획득한 트래픽 차트에서 기존에 최상위었던 referral, direct, not set이 하위로 내려간 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 앞서 설정한 두 가지 작업을 바탕으로 데이터 대시보드에서도 필터링을 쉽게 적용할 수 있었다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이제 모든 대시보드에서 로그인 여부와 캠페인을 기준으로 데이터를 확인할 수 있다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;예를 들면 페이스북 캠페인으로 얻은 유저들의 지표와 틱톡 캠페인으로 얻은 유저들의 지표들을 디테일하게 비교하여 우리가 집중해야 할 매체들을 찾을 수 있게 된 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;157&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxzA51/btrvEK8ajDA/QunR03NdvwyfMIdgvtPL10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxzA51/btrvEK8ajDA/QunR03NdvwyfMIdgvtPL10/img.png&quot; data-alt=&quot;새롭게 추가된 데이터 데시보드 필터 옵션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxzA51/btrvEK8ajDA/QunR03NdvwyfMIdgvtPL10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxzA51%2FbtrvEK8ajDA%2FQunR03NdvwyfMIdgvtPL10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1338&quot; height=&quot;157&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;157&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;새롭게 추가된 데이터 데시보드 필터 옵션&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구글 데이터 대시보드에 새로운 데이터 소스 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 프로덕트 매니저가 요구하는 지표들을 GA4와 데이터 대시보드가 제공하는 기본적인 기능으로 표현하기 어려울 때가 많다. 이를 극복하기 위해 gtag를 이용하여 커스텀 이벤트를 만들어 대응하고 있지만 부족함을 느끼고 있다. 예를 들어 `게임코치 온라인 유료 포인트를 가지고 있는 유저` 필터 옵션이나 `특정 이벤트를 기준 페이지별 발생 횟수`같은 지표를 구현하기 어렵다. 이를 극복하기 위해 Google BigQuery와 게임코치 온라인 DB를 대시보드의 데이터 소스로 추가하는 작업을 진행했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://support.google.com/analytics/answer/9358801?hl=ko&quot;&gt;Google BigQuery&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BigQuery는 대규모 데이터 세트에 대해서 쿼리를 신속하게 처리할 수 있는 클라우드 데이터 웨어하우스로 GA4에서 축적한 데이터를 기반으로 SQL과 유사한 구문을 사용하여 조회할 수 있는 기능 제공한다. 기존에 UA 버전에서의 GA에서는 BigQuery와 연결하는 BigQuery connector가 유료버전에만 포함되어 있었는데 GA4버전부터는 무료로 변경되어 손쉽게 사용할 수 있게 되었다. (BigQuery 자체는 유료이지만 무료 플랜으로도 충분히 사용 가능함)&lt;/li&gt;
&lt;li&gt;Google BigQuery로 GA4 데이터를 들여다보니 모든 데이터는 이벤트 형태로 저장하고 있어서, 이벤트 발생 시 함께 저장한 상세 데이터(이벤트 발생 위치, 유저 식별자, 이벤트 벨류 등)를 기준으로 검색하거나 그룹화할 수 있었다. 덕분에 프로덕트 매니저가 요구하는 다양한 이벤트 기반 지표들(채팅 이벤트가 어떤 위치에서 얼마나 발생하는지 등)을 시각화할 수 있었다. (GA4를 조회하는 빅쿼리를 시작한다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developers.google.com/analytics/bigquery/basic-queries&quot;&gt;구글 공식 문서&lt;/a&gt;를 강추한다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;게임코치 온라인 데이터베이스&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구글 데이터 대시보드는 MSSQL, MYSQL 등 다양한 데이터베이스를 데이터 소스로 사용할 수 있게 도와주는 커넥터를 지원한다. 또한 데이터 소스들을 연결하는 JOIN 기능을 지원하기 때문에 GA에서 수집한 유저 정보에 기반하여 데이터베이스 정보를 더해 확장하면 강력한 분석 환경을 제공할 수 있다.&lt;br /&gt;하지만 구글 데이터 대시보드에 우리 게임코치 온라인의 데이터베이스 접근권한을 부여하는 것은 보안상 위험할 뿐만 아니라 법적으로도 검토가 필요한 민감한 사항이기 때문에 연동을 진행하지 않고 내부망에 구성된 별도의 분석 툴을 이용하는 것으로 결정했다. 서비스 DB와 연계가 필요한 지표 요청이 계속되고 있기 때문에 민감한 정보를 조회할 수 없는 DB 엔드포인트를 별도로 준비하여 연결하는 방법을 백엔드 팀장님과 함께 계속 고민하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;A/B테스트 환경 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 최근 12주간 축적해온 개발 내용을 프로덕션에 반영하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://online.gamecoach.pro/&quot;&gt;게임코치 메인 페이지는&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명확한 CTA 버튼을 노출하고 있다. 페이지의 목표가 명확해지고 예산을 사용하여 마케팅을 진행하려다 보니 A/B테스트에 대한 니즈가 생겼고 해결안으로 Google Optimize를 선택했다. Optimize는 사용하게 된 이유로 몇 가지 장점이 있는데 실제 사용해본 경험을 바탕으로 소개한다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GA4와의 연동
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Optimize의 가장 큰 장점은 A/B테스트에서 가장 중요한 각 대안별 효과 측정을 GA4 데이터에 기반하여 자동으로 생성해주는 부분이다. 특히 A/B테스트를 생성할 때 테스트의 목적을 선택할 수 있으며, GA4에서 설정해둔 전환 이벤트를 선택할 수 있고, 부가적인 목표도 차순위 이벤트를 선택할 수 있기 때문에 A/B테스트 목적을 GA4와 일원화하고, 결과를 분석하는 뷰를 목적에 맞게 별도로 생성하는 수고를 덜 수 있다.&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;코드 수정이 필요 없는 대안 생성 툴&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Optimize에서는 A/B테스트를 진행할 대안을 생성하는 툴을 제공한다. 개발자가 아니더라도 클릭만으로 새로운 대안을 추가할 수 있으며 코드 상의 변화도 없기 때문에 배포나 개발팀 도움 없이 대안을 관리할 수 있다. (레이아웃을 변경하거나 노출 순서를 변경하는 등 매우 강력한 기능을 제공하는 것을 보고 감탄만...  )&lt;/li&gt;
&lt;li&gt;만약 서비스 프런트엔드를 Vue나 React를 이용하여 SSR형태로 개발했다면, 서버에서 랜더링 한 화면과 프론트에서 랜더링 한 화면이 다르기 때문에 hydration error가 발생할 수 있다. 이 경우 client에서만 렌더링 되도록 예전에 종선 개발자님이 공유한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://blog.bigpi.co/122?category=1210926&quot;&gt;client-only 컴포넌트&lt;/a&gt;와 같은 방법을 적용하면 해결할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;785&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oe0XN/btrvJxfJlnI/zfOsDjfMN1zXo78fFgTVjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oe0XN/btrvJxfJlnI/zfOsDjfMN1zXo78fFgTVjK/img.png&quot; data-alt=&quot;Optimize에서 새로운 대안을 수정하는 중&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oe0XN/btrvJxfJlnI/zfOsDjfMN1zXo78fFgTVjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foe0XN%2FbtrvJxfJlnI%2FzfOsDjfMN1zXo78fFgTVjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1149&quot; height=&quot;785&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;785&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Optimize에서 새로운 대안을 수정하는 중&amp;amp;amp;amp;amp;amp;amp;amp;amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터 대시보드를 구축하면서 어려웠던 부분&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 프로덕트 매니저가 필요한 데이터와 지표는 자연어 형태로 전달된다. 그리고 이런 요청들은 GA4, BigQuery, 데이터 대시보드, Optimize 등 앞서 소개한 데이터 소스와 툴들이 이해할 수 있는 문맥으로 변환되어야 한다. 데이터 지표를 만드는 과정 초반에는 툴들을 세팅하고 데이터 정합성을 맞추는 것이 어려웠지만, 현재는 매니저 분들의 자연어를 최대한 빈틈없이 기계어로 바꾸는 과정이 가장 어렵고 결과 만족도를 얻기 어려운 상황이다. 지표 생성을 요청 주시는 분들이 데이터 분석 환경과 친해진다면, 그리고 나의 번역 스킬을 높여 간다면 이런 어려움을 극복할 수 있다고 생각한다.(그래서 블로그도 열심히!✍) 울퉁불퉁 어려움 많은 비포장 도로 위에서 프로덕트 매니저와 협업하며 자연어를 기계어?로 번역한 예시를 첨부한다.  &lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자연어 - '1월 15일을 기준으로, 기존 서비스 이용자가 아니었던 사람들의 데이터를 분리해주세요.'&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;'서비스 이용자'라는 기준을 페이지 방문 여부로 결정할 것인지, 전환 이벤트 발생자로 잡을 것인지, 구매를 완료한 수강생으로 잡을 것인지에 대한 논의가 필요하고 데이터 요청자와 콘텍스트를 맞추어야만 결과 지표를 바라보는 시점도 맞출 수 있다.&lt;/li&gt;
&lt;li&gt;'1월 15일'이라는 기준을 충족하려면 앞서 논의한 '서비스 이용자'의 기준에 날짜 개념을 적용할 수 있어야 한다. GA4에서 날짜 기반으로 필터링 하기 애매한 것들이 있다. 예를 들어 '서비스 방문', '페이지 조회'를 기반으로 필터링하면 1년 전에 서비스를 마지막으로 방문한 유저가 재방문했을 경우 신규 방문자 속성을 가진 '기존' 방문자 이기 때문에 결과 분석 시 이런 예외 케이스에 대한 고려가 필요해진다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이런 상황에서 프로젝트 매니저와 '서비스 이용자', '기간'에 대한 논의(개발자의 애원이었을 지도.. &amp;zwj; )를 진행하고, 다른 예시 대시보드 참고하여 GA4 전환 이벤트 중 하나인 '구매자'를 기존 서비스 이용자로 구분자로 활용하고 데이터 대시보드 조회 기간을 수동으로 선택하여 '기존'이라는 조건은 적용하는 것으로 기계어 번역을 마쳤다. (프로젝트 매니저의 요구사항을 깔끔하게 구현하지 못한 것과 불완전할 수 있는 지표로 인해 번역 품질 만족도가 걱정된다. 어렵고 개선이 필요한 부분이다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다음 단계&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 지금까지 우리 서비스에서 발생하는 데이터를 수집하고, 팀원 모두 간편하게 확인할 수 있는 기반을 다졌다. 지금부터는 '제품 구매'라는 최종 목표로 더 정확하게 나아갈 수 있는 '중간 목표'를 만들어 데이터 대시보드의 실용성을 높이고 싶다. 예를 들면 스트리밍 서비스의 경우 수익이 발생하는 최종 목표가 '도네이션' 또는 '광고 등록'일 때, 최종 목표에 도달한 유저가 공통적으로 가지고 있는 이벤트를 분석하여 '중간 목표'를 '스트리밍 5분 신청'으로 찾아낼 수 있다. 반대로 '스트리밍 5분 지속 시청 여부'를 기준으로 유저를 분리하고 두 집단의 전환율을 비교하여 1차적으로 가설을 증명해 볼 수도 있다. 만약 '스트리밍 5분 지속 시청'이라는 이벤트가 전환율에 중요한 영향을 미친다면 이것을 '중간 목표'로 잡고 '최종 목표'보다 좀 더 명료한 계획과 실행, 증명을 할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 우리 서비스인 게임을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://online.gamecoach.pro/&quot;&gt;1:1로 강의하는 게임코치 온라인&lt;/a&gt;의 경우 '제품 구매'를 최종 목표로, '코치와 1:1 대화'를 중간 목표로 잡아 볼 수 있다. 하지만 이런 생각을 상상과 가설에 기반하지 않고 데이터에 기반하여 중간 목표 설정이 타당한지, 최종 목표에는 얼마나 영향을 미치는지, 우리의 작업이 중간 목표 달성률을 올렸는지 등을 데이터에 기반하여 판단해야만 한다. 다음 단계로 '중간 지표'를 찾고, 이를 통해 '최종 목표'에 긍정적인 영향을 미칠 수 있는 대시보드 실용성 향상에 집중해 보겠다. 조만간 즐거운 마음으로 데이터 대시보드 3편을 쓸 수 있기를 바라본다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;squar.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;776&quot;&gt;&lt;a href=&quot;https://blog.bigpi.co/65&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlmPRf/btrvJ0WfEzv/8RTROko4qK9djw5Ta9HZl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlmPRf%2FbtrvJ0WfEzv%2F8RTROko4qK9djw5Ta9HZl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;83&quot; height=&quot;83&quot; data-filename=&quot;squar.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;김병규&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;(bk@bigpi.co)&lt;br /&gt;&lt;/span&gt;새로움과 자유로움을 좋아하는 개발자입니다.&lt;br /&gt;프로덕트의 성장은 구성원의 성장으로부터 온다고 믿습니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>DATA</category>
      <category>A/B테스트</category>
      <category>GA4</category>
      <category>UTM</category>
      <category>게임코치온라인</category>
      <category>구글데이터스튜디오</category>
      <category>그로스해킹</category>
      <category>데이터대시보드</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/26</guid>
      <comments>https://bkim.tistory.com/26#entry26comment</comments>
      <pubDate>Fri, 11 Mar 2022 16:30:13 +0900</pubDate>
    </item>
    <item>
      <title>[애자일로 빅픽처를 그리다] 데이터 대시보드 feat. GA4</title>
      <link>https://bkim.tistory.com/25</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;들어가면서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 우리는 게임코치온라인(&lt;a href=&quot;https://online.gamecoach.pro/&quot;&gt;https://online.gamecoach.pro/&lt;/a&gt;) 서비스를 애자일 하게 개발하고 있다. 애자일의 가치와 효과를 경험하면서 목적지를 향해 (애자일 코치님의 팀 건강 검진 결과에 따르면 ) 즐겁게 항해하고 있으며 K-애자일로 변질되지 않도록 부단히 노력하고 있다. 애자일은 함께 일하기 위한 관점으로써 우리가 무엇을-어떻게 만들어야 할지 안내하는 눈이 되어준다. 우리의 시야를 더욱 분명하게 개선하기 위한 노력 중 하나로 데이터 대시보드를 만들고 있으며, 현재까지의 과정을 공유한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;애자일을 위한 데이터 대시보드?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 스타트업은 모호함을 명확함으로 바꿔가는 과정이라고 생각한다.(by&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=qOC0VfqgPS4&amp;amp;t=1256s&quot;&gt;모호좌&lt;span&gt; &amp;zwj; &lt;/span&gt;&lt;/a&gt;)&amp;nbsp; 우리는 끊임없이 무엇을 할 수 있는지, 언제까지 할 수 있는지에 대한 물음에 대답을 해야 하며, 결과물을 통해 어떤 성과를 얻을 수 있을지(또한 무엇을 얻었는지) 예측할 수 있어야 한다. 애자일 하다는 것은 어쩌면 이러한 질문들에 조금 더 정확한 대답을 찾기 위해 노력한다는 것일 수 있겠다. 하지만 완벽한 애자일 방법론이 완벽한 답변을 만들 수는 없다. 앞서 말했듯 애자일은 모호함을 선명하게 보기 위한 관점이기 때문이다. 우리는 선명한 시야를 가지고 서비스에 맞는 정답을 향해 나아가야만 정답에 가까워질 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 애자일을 위한 데이터는 우리 관점의 정확함을 검사할 수 있는 시력검사표 역할을 한다. 그것은 서비스가 현재 위치하는 곳을 제대로 파악하고, 우리가 예측했던 것이 얼마나 정확했는지 혹은 얼마나 틀렸는지를 바라볼 수 있는 검사 지표로써 동작할 것이다. 매번 돌아오는 스프린트의 성과를 측정하지 않으면서, 좋은 서비스로 나아가는 것을 기대한다면 복권 당첨을 기대하는 것과 다를 바 없다. 스케이트 보드의 바퀴가 제대로 굴러가지 않는 걸 모른 채 핸들을 추가한다면 그것은 킥보드로써 역할을 할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 애자일을 위한 여정에 동참하고, 지속적인 물음에 대답하기 위해 데이터 대시보드를 만들고 있다. 현재까지 구성한 대시보드는 다음과 같은 목표를 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 팀의 모든 구성원이 쉽게 확인할 수 있어야 한다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt; 데이터에 기반하여 아이디어를 구현할 수 있는 틀을 제공 해야 한다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt; 기능 추가/변경 시점을 기준으로 우리가 의도한 바를 달성하였는지 확인할 수 있어야 한다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt; 설계자의 질문에 대답할 수 있어야 한다. ex) 특정 기능 사용률, 수정한 기능에서의 구매 전환 변동률 등&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존 데이터 대시보드의 아쉬웠던 부분&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 레벨업지지 플랫폼을 개발하기 위해 Google 애널리틱스(이하 GA)와 아파치 제플린(디자인 툴 Zeplin 과는 다름)을 이용한 데이터 대시보드를 이용하고 있었다. 아파치 제플린을 이용하여 데이터베이스와 로그 저장소에 있는 데이터를 상세하게 조회할 수 있고 GA를 통해 웹에서 발생하는 이벤트들을 파악할 수 있지만 애자일 측면에서 몇 가지 아쉬운 부분이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;대시보드로써 스토리가 부재하다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터 대시보드는 표현하고자 하는 스토리가 분명해야 설득력 있게 데이터를 전달할 수 있다. 하지만 제플린으로 구성한 대시보드는 기능별(유저 사용성이 아닌)로만 대시보드가 분리되어있어 지표들 간의 상호관계가 없다.&lt;br /&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;아파치 제플린으로 구현된 데이터 대시보드는 근엄하고 위압감이 느껴진다. 개발자에게는 각종 테이블에서 뿜어내는 숫자들과 실시간으로 업데이트되는 데이터들이 다정하게 다가갈 수 있지만, 서비스를 운영하고 기획하는 분들에게는 대화를 거부하는 답정너 대시보드처럼 보일 수 있다.&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;545&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNQKpt/btrvH0bLF2f/ukXnqkveaZDfaYDnemh95K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNQKpt/btrvH0bLF2f/ukXnqkveaZDfaYDnemh95K/img.png&quot; data-alt=&quot;apache zeppelin 예시화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNQKpt/btrvH0bLF2f/ukXnqkveaZDfaYDnemh95K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNQKpt%2FbtrvH0bLF2f%2FukXnqkveaZDfaYDnemh95K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1254&quot; height=&quot;545&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;545&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;apache zeppelin 예시화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;유저와 서비스 간의 상호작용을 확인하기 어렵고, 특정 시점 기준으로 데이터를 비교하기 어렵다.&lt;/span&gt;&lt;br /&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRPHvX/btrqCaYinlf/BOVl0Ybm7Wgo9hn2AFw3Gk/img.png&quot; data-lightbox=&quot;lightbox&quot; data-alt=&quot;apache zeppelin 예시화면&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;GA로 유저 이벤트를 수집하고 있었으나 이를 들여다볼 커스텀 보고서가 없었기에 이벤트 발생 빈도, 종류 등 단편적인 정보만 확인하고 있었다. 또한 커스텀 보고서를 이용하더라도 GA를 이용해서 확인할 수 있는 이벤트 상세 정보 (이벤트 벨류, 이벤트 로케이션 등)를 파악하기 어려운 문제점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;제플린으로 표현하는 차트들은 기간을 기준으로 비교하기 어렵다. (GA에서는 최근 2주에 대한 데이터를 조회하면 자동으로 과거 4~3주 차의 데이터와 비교해서 지표 증감률을 표현해준다.)&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;새롭게 추가된 데이터 대시보드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 게임코치 온라인 서비스를 개발하는 팀원 전체가 이해하기 쉽고 친근하게 다가갈 수 있는 대시보드 형태가 무엇일까 고민하다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;a href=&quot;https://post.naver.com/viewer/postView.naver?volumeNo=29060358&amp;amp;memberNo=2647347&quot;&gt;AARRR 해적 지표를&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;구글 데이터 스튜디오로 구현하는 것을 목표로 첫 번째 대시보드&lt;/b&gt;를 만들었다. 우리 서비스의 현재 상황을 파악할 수 있고 개선해야 할 포인트를 드러내서 새로운 아이디어를 유도할 수 있는 지표라고 생각했기 때문이다. 두&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;번째로 특정 기능에 집중하지 않고, 유저 스토리를 기준으로 데이터를 표현하는 대시보드를 추가했다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;예를 들면 '코치 찾기 스토리' 대시보드의 경우 '유저들은 어떤 추천 태그를 많이 클릭하는가?', '유저들은 어떤 정렬을 많이 적용하는가?', '유저들은 코치 찾기 페이지를 얼마나 탐색하는가?'에 대한 기획자의 질문에 대답할 수 있는 데이터를 중심으로 시각화해서 데이터 가독성을 높이는데 집중한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AARRR FUNNEL 대시보드&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &amp;nbsp;&lt;/span&gt;서비스를 이용하는 유저의 획득부터 수익, 레퍼럴까지 FUNNEL(깔때기) 형태로 데이터를 표현하여 위에서부터 아래로 데이터를 읽어 갈 수 있도록 구성했다. 데이터를 읽어가는 방향을 제공한다는 점에서, 기존에 사용 중인 GA 보고서와 제플린의 차트와 가장 대비되는 부분이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &amp;nbsp;&lt;/span&gt;대시보드 구성을 위한 데이터 소스로 GA4(새로운 버전의 GA로 빅쿼리를 무료버전에서도 사용할 수 있다.)와 GA3(GA4 이전 버전인 UA 버전), Google BigQuery를 모두 사용하여 GA에 친숙하지 않은 사용자도 배포일 기준으로 방문자나 전환(수익)이 얼마나 발생했는지 쉽게 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &amp;nbsp;&lt;/span&gt;AARRR 대시보드를 통해서 우리가 집중해야 하는 부분을 파악할 수 있고 &quot;새로운 기능 A는 무엇을 개선하기 위함인가?&quot;, &quot;이번에 배포된 기능 B는 우리가 개선하고자 했던 목표를 달성했는가?&quot; 등 팀원들의 질문에 대답할 수 있다. 그리고 데이터에 기반하여 지나간 스프린트를 회고하고 우리가 했던 예측과 대답들이 얼마나 정확했는지 판단할 수 있기 때문에 우리 대답의 정답률을 높이는데 도움이 될 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;1170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KLYcG/btrvE3N1QZ4/Qb7adCg3HkrzMLSU5wXgE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KLYcG/btrvE3N1QZ4/Qb7adCg3HkrzMLSU5wXgE0/img.png&quot; data-alt=&quot;게임코치온라인 개발환경 AARRR 대시보드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KLYcG/btrvE3N1QZ4/Qb7adCg3HkrzMLSU5wXgE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKLYcG%2FbtrvE3N1QZ4%2FQb7adCg3HkrzMLSU5wXgE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;757&quot; height=&quot;1170&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;1170&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;게임코치온라인 개발환경 AARRR 대시보드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;코치 찾기 페이지 대시보드&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;751&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgZjc2/btrvIxNXnSg/4KpCqSIDatpFk2ijxXkQnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgZjc2/btrvIxNXnSg/4KpCqSIDatpFk2ijxXkQnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgZjc2/btrvIxNXnSg/4KpCqSIDatpFk2ijxXkQnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgZjc2%2FbtrvIxNXnSg%2F4KpCqSIDatpFk2ijxXkQnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;435&quot; height=&quot;751&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;751&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&amp;nbsp;스프린트 리뷰&amp;amp;회고 시간을 통해 AARRR대시보드를 팀에 공유 한 뒤, 서비스 전체 관점이 아닌 에픽이나 유저 스토리 기준의 대시보드의 필요성에 대해서 대화를 나누었다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;nbsp; 우리는 에픽이나 스토리의 성과를 측정할 수 있는 지표를 데이터 기반으로 설정하여 무엇이 목표인지 분명히 하고자 했다. 또한 유저 스토리 적용 전부터 부재되어있던 데이터를 미리 쌓아 기능 배포 이전과 이후를 비교할 수 있는 환경을 구축하고자 했다. (스토리 적용 전/후 비교를 통해 에픽의 성공 여부와 개선점을 다시 찾을 수 있기 때문에)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;nbsp; 그래서 에픽을 작성하는 단계에서부터 에픽의 목적과 효과를 데이터에 기반하여 설정하였고, 유저에게 개발 내용이 전달되었을 때 변화를 측정할 수 있도록 데이터 수집 요청 일감을 스토리 개발과 같은 스프린트에 추가하여 데이터 대시보드 구성을 하나의 업무로서 진행하게 되었다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&amp;nbsp;에픽이나 유저 스토리 기반의 데이터 대시보드는 유저의 클릭, 스크롤 상황 등 DB에 저장하지 않는 단순한 유저 상호작용을 모아 메인 데이터로 사용한다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;그렇기 때문에 GA4, GA3(UA버전)을 데이터 소스로 만들었던 AARRR대시보드와는 달리 GA4로 수집하고 있는 유저 이벤트를 좀 더 상세히 분석해야만 했고 GA4를 연동한 구글 BigQuery를 데이터 소스로 추가하였다. GA4 &amp;lt;-&amp;gt; BigQuery를 이용하면 이벤트의 상세 내용까지 추출할 수 있고, 데이터 요청자의 질문에 더 상세하게 대답할 수&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;있게 때문에 데이터 대시보드를 구축하는데 큰 도움이 되었다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1097&quot; data-origin-height=&quot;1097&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLHf2J/btrvH0JAFSX/BGkkp4zdFkvu6i8sczBGVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLHf2J/btrvH0JAFSX/BGkkp4zdFkvu6i8sczBGVk/img.png&quot; data-alt=&quot;게임코치 온라인 개발환경 코치찾기 대시보드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLHf2J/btrvH0JAFSX/BGkkp4zdFkvu6i8sczBGVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLHf2J%2FbtrvH0JAFSX%2FBGkkp4zdFkvu6i8sczBGVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1097&quot; height=&quot;1097&quot; data-origin-width=&quot;1097&quot; data-origin-height=&quot;1097&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;게임코치 온라인 개발환경 코치찾기 대시보드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-size: 1.44em; letter-spacing: -1px;&quot;&gt;앞으로 개선이 필요한 부분&lt;/span&gt;&lt;br /&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F9rFW/btrqBfetRxW/0v8C1j0cXeNf0B5TFBd0A1/img.png&quot; data-lightbox=&quot;lightbox&quot; data-alt=&quot;레벨업코칭 개발환경 코치찾기 대시보드&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 애자일을 위한 데이터 대시보드를 공개하고, 다양한 의견들이 더해지면서 개선이 필요한 부분들을 찾을 수 있었다. 수강 유저와 코칭 유저로 고객군을 분리하는 것, GA 유저 획득 소스가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://support.google.com/analytics/answer/11080067?hl=en&quot;&gt;not set과 direct&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;부분을 분석하는 것 등 공감되는 부분이 많았다. 의견들을 반영하여 대시보드를 개선하기 위해 다음과 같은 작업을 진행할 계획이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; GA 수집 데이터 상세화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt; 고객군 분리: 게임코치 온라인은 코치님과 수강생을 연결하는 서비스를 제공하기 때문에, 고객군을 수강 유저와 코칭 유저로 나눌 수 있다. 두 개의 고객군에게 제공하는 서비스와 집중해야 할 데이터가 다르기 때문에 대시보드도 분리하여 볼 수 있는 기능이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&amp;nbsp;유저 획득 들여다보기: GA특성상 많은 유저 획득이 not set이나, direct로 집계된다. AARRR대시보드의 분석 첫 단계로 획득 단계가 구체화될수록 기초를 단단하게 할 수 있을 것이다. 유저 획득을 상세화하고 구분하는 것은 GA를 사용하는 많은 팀들이 같이 고민하는 이슈로 UTM, 뷰저블 등 다양한 방법을 이용하여 not set과 direct를 줄여보려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 대시보드 데이터 리소스 추가 &amp;amp; 연결(Join)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&amp;nbsp;코칭 서비스의 친구 초대 이벤트를 상세 추적하거나, 프로모션에 투입된 비용 대비 유적 획득 비용을 계산하는 대시보드를 작업하기 위해서는 GA와 서비스 DB, 광고 비용 정보 등 다양한 데이터 리소스를 연결(Join) 해서 보아야 한다. 예를 들어 GA에서 추적한 데이터와 코칭 서비스 DB를 연결하여 대시보드를 구성한다면 구매 유저의 수강 횟수나, 잔여 포인트 현황 등을 함께 볼 수 있어 좀 더 리더블한 대시보드를 만들 수 있을 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; &amp;nbsp;우리는 더 좋은 서비스를 만들기 위해 애자일 하게 일하고 있다. 지속적으로 쌓아온 데이터를 분석하여 예측을 하고 유저와 상호작용을 분석하여 예측 결과를 평가한다. 그리고 더 나은 예측을 기대한다. 좋은 서비스를 만드는 것은 서비스를 만드는 사람들의 공통적인 목표일 것이다. (애자일 방법론을 떠나서라도) 팀에서 활용하고 있는 데이터에 스토리를 더하고 더 나은 예측을 위한 노력은 좋은 서비스를 만드는데 도움이 될 것이라 믿는다. 계속해서 발전시켜나갈 데이터 대시보드가 더 좋은 제품을 위한 우리 팀의 노력에 보탬이 될 수 있으면 좋겠다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;squar.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;776&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cliAw1/btrvI2GUSt1/OcFbX2BHlIaR3qfkkFsqZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cliAw1/btrvI2GUSt1/OcFbX2BHlIaR3qfkkFsqZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cliAw1/btrvI2GUSt1/OcFbX2BHlIaR3qfkkFsqZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcliAw1%2FbtrvI2GUSt1%2FOcFbX2BHlIaR3qfkkFsqZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;83&quot; height=&quot;776&quot; data-filename=&quot;squar.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;김병규&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;(&lt;/span&gt;&lt;span&gt;bk@bigpi.co)&lt;br /&gt;&lt;/span&gt;새로움과 자유로움을 좋아하는 개발자입니다.&lt;br /&gt;프로덕트의 성장은 구성원의 성장으로부터 온다고 믿습니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <category>DATA</category>
      <category>aarrr</category>
      <category>GA4</category>
      <category>gca</category>
      <category>게임코치온라인</category>
      <category>데이터대시보드</category>
      <category>데이터스튜디오</category>
      <category>애자일</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/25</guid>
      <comments>https://bkim.tistory.com/25#entry25comment</comments>
      <pubDate>Fri, 11 Mar 2022 16:27:34 +0900</pubDate>
    </item>
    <item>
      <title>Spring Batch 와 Jekins 를 이용하여 간단한 배치 환경 구성하기</title>
      <link>https://bkim.tistory.com/23</link>
      <description>&lt;h2&gt;개요&lt;/h2&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;2분 마다 시총 상위 100개 코인에 대한 가격정보를 크롤링하려 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;크롤링을 위해서는 Batch Job 과 Scheduler가 필요한데, 어떤 환경으로 구성할까 고민하다 Batch Job은 Spring Batch로 Scheduler는 Jekins로 구성했다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Spring Batch를 쓴 이유&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;1. Spring boot를 사용중이라 기존에 만들어둔 Service를 재사용할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;2. Transaction, Datasouce 관리가 편하다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;3. 익숙한 환경 (Java, RestTemplate, Error handling 등등)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Jekins를 쓴 이유&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;1. GUI 환경 Batch Job&amp;nbsp;관리가 편리하다. (상태확인, 실행 주기 관리, 로그 확인 등등)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;2. Jenkins에서 Jar 형태의 Batch Job Application 을 직접&amp;nbsp;실행할 경우, 로그 확인이 편리&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;문제점&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Q&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Spring Batch 를 단순 크롤링 작업으로만 사용하기에는 오버스팩!&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;A&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;오버스팩인것은 맞다. 하지만 구현 속도는 가장 빠르다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Q &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Spring Batch 는 Database Table로 Job을 관리하는데 Jekins로 실행한다고?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;A &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Database Table를 이용하지 않고,&amp;nbsp;In - Memory 에서 작동하도록 설정했다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Q &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Batch Application를 이중화 하려면?&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;A &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;이중화가 불가능한 문제다. 다만, 배포를 위한 중단시간이 제로에 가깝고, 잡을 분리하는 등 운영방식으로 해결할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;구현&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;1. 스프링 배치 설정&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Spring Batch 의존성 추가 (Spring boot 2.1 기준)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Consolas';font-size:10.5pt;&quot;&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;  &amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;  &amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-batch&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Batch Config, Batch Job&amp;nbsp;생성&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;(InMemoryBatchConfigurer는 따로 생성했다.)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Consolas';font-size:10.5pt;&quot;&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Configuration&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@EnableBatchProcessing&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public class &lt;/span&gt;BatchJobConfig {&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Autowired&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;JobBuilderFactory &lt;span style=&quot;color:#9876aa;&quot;&gt;jobBuilderFactory&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Autowired&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;StepBuilderFactory &lt;span style=&quot;color:#9876aa;&quot;&gt;stepBuilderFactory&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Bean&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;BatchConfigurer &lt;span style=&quot;color:#ffc66d;&quot;&gt;batchConfigurer&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return new &lt;/span&gt;InMemoryBatchConfigurer()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Autowired&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;private &lt;/span&gt;UpdateTop100CoinPriceTasklet &lt;span style=&quot;color:#9876aa;&quot;&gt;updateTop100CoinPriceTasklet&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Bean&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;PlatformTransactionManager &lt;span style=&quot;color:#ffc66d;&quot;&gt;transactionManager&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return new &lt;/span&gt;ResourcelessTransactionManager()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Bean&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;Job &lt;span style=&quot;color:#ffc66d;&quot;&gt;updateTop100CoinPriceJob&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;jobBuilderFactory&lt;/span&gt;.get(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;updateTop100CoinPrice&quot;&lt;/span&gt;)&lt;br /&gt;            .start(updateTop100CoinPrice())&lt;br /&gt;            .build()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Bean&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;Step &lt;span style=&quot;color:#ffc66d;&quot;&gt;updateTop100CoinPrice&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;stepBuilderFactory&lt;/span&gt;.get(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;updateTop100CoinPrice&quot;&lt;/span&gt;)&lt;br /&gt;            .tasklet(&lt;span style=&quot;color:#9876aa;&quot;&gt;updateTop100CoinPriceTasklet&lt;/span&gt;)&lt;br /&gt;            .build()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Batch Tasklet 생성&lt;br /&gt;Tasklet과&amp;nbsp;InitializingBean을 구현하면 된고&amp;nbsp;RepeatStatus를 통해 Tasklet 반복여부를 선택할 수 있다.&lt;br /&gt;Tasklet에서 실행시킬 로직은 기존 Service Bean 주입을 통해 해결할 수 있어서 편&lt;/b&gt;&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Consolas';font-size:10.5pt;&quot;&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Component&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public class &lt;/span&gt;UpdateTop100CoinPriceTasklet &lt;span style=&quot;color:#cc7832;&quot;&gt;implements &lt;/span&gt;Tasklet&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;/span&gt;InitializingBean {&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Autowired&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;MarketCapService &lt;span style=&quot;color:#9876aa;&quot;&gt;marketCapService&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;RepeatStatus &lt;span style=&quot;color:#ffc66d;&quot;&gt;execute&lt;/span&gt;(StepContribution contribution&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;/span&gt;ChunkContext chunkContext) &lt;span style=&quot;color:#cc7832;&quot;&gt;throws &lt;/span&gt;Exception {&lt;br /&gt;        &lt;span style=&quot;color:#9876aa;&quot;&gt;marketCapService&lt;/span&gt;.updateTop100CoinPrice()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        return &lt;/span&gt;RepeatStatus.&lt;span style=&quot;color:#9876aa;font-style:italic;&quot;&gt;FINISHED&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public void &lt;/span&gt;&lt;span style=&quot;color:#ffc66d;&quot;&gt;afterPropertiesSet&lt;/span&gt;() &lt;span style=&quot;color:#cc7832;&quot;&gt;throws &lt;/span&gt;Exception {&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;In - Memory&amp;nbsp;Batch Configurer 설정&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Database Table로 Job을 관리하면 여러모로 신경써야할게 많다. 단순한 목적에 맞게 Memory에서 관리하자.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Consolas';font-size:10.5pt;&quot;&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public class &lt;/span&gt;InMemoryBatchConfigurer &lt;span style=&quot;color:#cc7832;&quot;&gt;implements &lt;/span&gt;BatchConfigurer {&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#cc7832;&quot;&gt;private &lt;/span&gt;PlatformTransactionManager &lt;span style=&quot;color:#9876aa;&quot;&gt;transactionManager&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    private &lt;/span&gt;JobRepository &lt;span style=&quot;color:#9876aa;&quot;&gt;jobRepository&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    private &lt;/span&gt;JobLauncher &lt;span style=&quot;color:#9876aa;&quot;&gt;jobLauncher&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    private &lt;/span&gt;JobExplorer &lt;span style=&quot;color:#9876aa;&quot;&gt;jobExplorer&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;PlatformTransactionManager &lt;span style=&quot;color:#ffc66d;&quot;&gt;getTransactionManager&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;transactionManager&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;JobRepository &lt;span style=&quot;color:#ffc66d;&quot;&gt;getJobRepository&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;jobRepository&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;JobLauncher &lt;span style=&quot;color:#ffc66d;&quot;&gt;getJobLauncher&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;jobLauncher&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;JobExplorer &lt;span style=&quot;color:#ffc66d;&quot;&gt;getJobExplorer&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;jobExplorer&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@PostConstruct&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public void &lt;/span&gt;&lt;span style=&quot;color:#ffc66d;&quot;&gt;initialize&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;if &lt;/span&gt;(&lt;span style=&quot;color:#cc7832;&quot;&gt;this&lt;/span&gt;.&lt;span style=&quot;color:#9876aa;&quot;&gt;transactionManager &lt;/span&gt;== &lt;span style=&quot;color:#cc7832;&quot;&gt;null&lt;/span&gt;) {&lt;br /&gt;            &lt;span style=&quot;color:#cc7832;&quot;&gt;this&lt;/span&gt;.&lt;span style=&quot;color:#9876aa;&quot;&gt;transactionManager &lt;/span&gt;= &lt;span style=&quot;color:#cc7832;&quot;&gt;new &lt;/span&gt;ResourcelessTransactionManager()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        &lt;/span&gt;}&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;try &lt;/span&gt;{&lt;br /&gt;            MapJobRepositoryFactoryBean jobRepositoryFactoryBean = &lt;br /&gt;                &lt;span style=&quot;color:#cc7832;&quot;&gt;new &lt;/span&gt;MapJobRepositoryFactoryBean(&lt;span style=&quot;color:#cc7832;&quot;&gt;this&lt;/span&gt;.&lt;span style=&quot;color:#9876aa;&quot;&gt;transactionManager&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            &lt;/span&gt;jobRepositoryFactoryBean.afterPropertiesSet()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            this&lt;/span&gt;.&lt;span style=&quot;color:#9876aa;&quot;&gt;jobRepository &lt;/span&gt;= jobRepositoryFactoryBean.getObject()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            &lt;/span&gt;MapJobExplorerFactoryBean jobExplorerFactoryBean = &lt;br /&gt;                &lt;span style=&quot;color:#cc7832;&quot;&gt;new &lt;/span&gt;MapJobExplorerFactoryBean(jobRepositoryFactoryBean)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            &lt;/span&gt;jobExplorerFactoryBean.afterPropertiesSet()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            this&lt;/span&gt;.&lt;span style=&quot;color:#9876aa;&quot;&gt;jobExplorer &lt;/span&gt;= jobExplorerFactoryBean.getObject()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            &lt;/span&gt;SimpleJobLauncher jobLauncher = &lt;span style=&quot;color:#cc7832;&quot;&gt;new &lt;/span&gt;SimpleJobLauncher()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            &lt;/span&gt;jobLauncher.setJobRepository(&lt;span style=&quot;color:#9876aa;&quot;&gt;jobRepository&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            &lt;/span&gt;jobLauncher.afterPropertiesSet()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            this&lt;/span&gt;.&lt;span style=&quot;color:#9876aa;&quot;&gt;jobLauncher &lt;/span&gt;= jobLauncher&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        &lt;/span&gt;} &lt;span style=&quot;color:#cc7832;&quot;&gt;catch &lt;/span&gt;(Exception e) {&lt;br /&gt;            &lt;span style=&quot;color:#cc7832;&quot;&gt;throw new &lt;/span&gt;BatchConfigurationException(e)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        &lt;/span&gt;}&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;2. Application 실행환경 설정&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Application Type을 WEB에서 NONE으로 변경했다. 이제 포트를 찾지 않아도 되어서 여러 Job들을 실행할 수 있다. (프로세스 생성비용은 늘어나지만..)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Spring Batch CommandLineJobRunner 를 사용할까 하다가, 어렵고 과한것 같아서 Application 실행 변수로 Batch Job 명을 전달 받아 실행하는 방식으로 세팅했다.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Consolas';font-size:10.5pt;&quot;&gt;&lt;p&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Slf4j&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@SpringBootApplication&lt;/span&gt;(&lt;span style=&quot;color:#d0d0ff;&quot;&gt;exclude &lt;/span&gt;= {&lt;br /&gt;    DataSourceAutoConfiguration.&lt;span style=&quot;color:#cc7832;&quot;&gt;class,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;DataSourceTransactionManagerAutoConfiguration.&lt;span style=&quot;color:#cc7832;&quot;&gt;class,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;HibernateJpaAutoConfiguration.&lt;span style=&quot;color:#cc7832;&quot;&gt;class&lt;br /&gt;&lt;/span&gt;})&lt;br /&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@EnableAsync&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@EnableScheduling&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@EnableCaching&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@EnableTransactionManagement&lt;/span&gt;(&lt;span style=&quot;color:#d0d0ff;&quot;&gt;proxyTargetClass &lt;/span&gt;= &lt;span style=&quot;color:#cc7832;&quot;&gt;true&lt;/span&gt;)&lt;br /&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@EnableJpaRepositories&lt;/span&gt;(&lt;span style=&quot;color:#d0d0ff;&quot;&gt;basePackages &lt;/span&gt;= &lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;com.happy.life&quot;&lt;/span&gt;)&lt;br /&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public class &lt;/span&gt;BatchApplication {&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#cc7832;&quot;&gt;public static void &lt;/span&gt;&lt;span style=&quot;color:#ffc66d;&quot;&gt;main&lt;/span&gt;(String[] args)&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;throws &lt;/span&gt;JobParametersInvalidException&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;/span&gt;JobExecutionAlreadyRunningException&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        &lt;/span&gt;JobRestartException&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;/span&gt;JobInstanceAlreadyCompleteException {&lt;br /&gt;&lt;br /&gt;        SpringApplication app = &lt;span style=&quot;color:#cc7832;&quot;&gt;new &lt;/span&gt;SpringApplication(BatchApplication.&lt;span style=&quot;color:#cc7832;&quot;&gt;class&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        &lt;/span&gt;app.setWebApplicationType(WebApplicationType.&lt;span style=&quot;color:#9876aa;font-style:italic;&quot;&gt;NONE&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        &lt;/span&gt;ConfigurableApplicationContext ctx = app.run(args)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        &lt;/span&gt;JobLauncher jobLauncher = ctx.getBean(JobLauncher.&lt;span style=&quot;color:#cc7832;&quot;&gt;class&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        if &lt;/span&gt;(args.&lt;span style=&quot;color:#9876aa;&quot;&gt;length &lt;/span&gt;&amp;gt; &lt;span style=&quot;color:#6897bb;&quot;&gt;0&lt;/span&gt;) {&lt;br /&gt;            Job job = ctx.getBean(args[&lt;span style=&quot;color:#6897bb;&quot;&gt;0&lt;/span&gt;]&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;/span&gt;Job.&lt;span style=&quot;color:#cc7832;&quot;&gt;class&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            &lt;/span&gt;jobLauncher.run(job&lt;span style=&quot;color:#cc7832;&quot;&gt;, new &lt;/span&gt;JobParameters())&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        &lt;/span&gt;} &lt;span style=&quot;color:#cc7832;&quot;&gt;else &lt;/span&gt;{&lt;span style=&quot;color:#808080;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#808080;&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;color:#9876aa;font-style:italic;&quot;&gt;log&lt;/span&gt;.error(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#6a8759;font-family:'굴림체';&quot;&gt;배치 잡 이름을 입력해 주세요&lt;/span&gt;&lt;span style=&quot;color:#6a8759;&quot;&gt;. EX) {}&quot;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;java -jar app.jar updateTop100CoinPriceJob&quot;&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;        &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;        System.&lt;span style=&quot;font-style:italic;&quot;&gt;exit&lt;/span&gt;(&lt;span style=&quot;color:#6897bb;&quot;&gt;0&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;}&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;3. 젠킨스 설정&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;젠킨스를 설치하고 깃헙 연동하는 과정은 생략한다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;배포하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;젠킨스에서 Freestyle project를 하나 만들어서 Batch Application을 배포하자.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Github에서 소스를 받아와&amp;nbsp;maven build하는 기본 빌드 이후에 jar를 복사한다.&amp;nbsp; yes|cp -rf 옵션을 줘서 항상 덮어쓰기 하도록한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;이렇게 하면 순단없이 아주 빠르게 배포? 한다고 말할 수&amp;nbsp;있지않을까? 호호호호&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994ECD385C63A85526&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994ECD385C63A85526&quot; width=&quot;900&quot; height=&quot;497&quot; filename=&quot;배포.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;실행하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;배포한 jar를 실행한다. Jenkins의 Build periodically값을 조정해서 2분만다 실행하도록 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;그리고 Execute shell 에서 Java -jar 옵션으로 배치를 실행한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99147D3E5C63A96D22&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99147D3E5C63A96D22&quot; width=&quot;900&quot; height=&quot;594&quot; filename=&quot;배포.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;결과 확인&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Job에서 뱉어내는 로그들을 잘 기록하면서 수행된 것을 확인할 수 있다. 오예 끝~!&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 727px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998F553D5C63A9DD21&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998F553D5C63A9DD21&quot; width=&quot;727&quot; height=&quot;1155&quot; filename=&quot;배포.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;결론&lt;/h2&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Spring Batch가 소잡는 칼이라 닭을 더 쉽게 잡을 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>SPRING</category>
      <category>Crawling</category>
      <category>in memory</category>
      <category>jenkins</category>
      <category>Scheduler</category>
      <category>spring Batch</category>
      <category>스케쥴링</category>
      <category>스프링 배치</category>
      <category>인메모리</category>
      <category>젠킨스</category>
      <category>코인 가격</category>
      <category>크롤링</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/23</guid>
      <comments>https://bkim.tistory.com/23#entry23comment</comments>
      <pubDate>Wed, 13 Feb 2019 14:28:22 +0900</pubDate>
    </item>
    <item>
      <title>Spring batch의 transaction manager bean 중복 문제 해결하기 (feat Spring boot 2.1)</title>
      <link>https://bkim.tistory.com/22</link>
      <description>&lt;h2&gt;문제&lt;/h2&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Spring Batch를 사용하기 위해 Maven 의존성을 추가하고, BatchConfig.java를 설정을 완료했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;그리고 배치를 시작하는 순간&amp;nbsp;transactionManager bean이 중복선언 되었다는 에러를 마주했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;배치에서 새로 생성한 transactionManager 때문에,&amp;nbsp;기존 프로젝트에서 사용하던&amp;nbsp;기존의 transacrionManager bean을 등록할 수 없다는 이유였다.&lt;/span&gt;&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Consolas';font-size:10.5pt;&quot;&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Configuration&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@EnableBatchProcessing&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public class &lt;/span&gt;BatchJobConfig {&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Autowired&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;JobBuilderFactory &lt;span style=&quot;color:#9876aa;&quot;&gt;jobBuilderFactory&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Autowired&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;StepBuilderFactory &lt;span style=&quot;color:#9876aa;&quot;&gt;stepBuilderFactory&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@Bean&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;Job &lt;span style=&quot;color:#ffc66d;&quot;&gt;updateSomethingJob&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;jobBuilderFactory&lt;/span&gt;.get(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;updateSomethingJob&quot;&lt;/span&gt;)&lt;br /&gt;            .start(somethingStep1())&lt;br /&gt;            .build()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color:#bbb529;&quot;&gt;@Bean&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public &lt;/span&gt;Step &lt;span style=&quot;color:#ffc66d;&quot;&gt;somethingStep1&lt;/span&gt;() {&lt;br /&gt;        &lt;span style=&quot;color:#cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;stepBuilderFactory&lt;/span&gt;.get(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;updateSomethingJobStep1&quot;&lt;/span&gt;)&lt;br /&gt;            .tasklet((contribution&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;/span&gt;chunkContext) -&amp;gt; {&lt;br /&gt;                &lt;span style=&quot;color:#9876aa;font-style:italic;&quot;&gt;log&lt;/span&gt;.info(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;Running UpdateSomethingJobStep1...&quot;&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;                return &lt;/span&gt;RepeatStatus.&lt;span style=&quot;color:#9876aa;font-style:italic;&quot;&gt;FINISHED&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;            &lt;/span&gt;})&lt;br /&gt;            .build()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;pre style=&quot;background-color: rgb(43, 43, 43);&quot;&gt;&lt;p&gt;&lt;font color=&quot;#a9b7c6&quot; face=&quot;Consolas&quot;&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;APPLICATION FAILED TO START
***************************
Description:
&lt;br /&gt;&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font color=&quot;#a9b7c6&quot; face=&quot;Consolas&quot;&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;The bean 'transactionManager', defined in class path resource [...], 
could not be registered. A bean with that name has already been defined in 
class path resource [&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;SimpleBatchConfiguration.class&lt;/span&gt;] 
and overriding is disabled.

Action:
Consider renaming one of the beans or enabling overriding 
by setting spring.main.allow-bean-definition-overriding=true&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;/pre&gt;&lt;h2&gt;해결 시도&lt;/h2&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&quot;아 왜 배치용 transactionManager&amp;nbsp;Bean 이름을 'transactionManager'로 한거야...&amp;nbsp;batchTransactionManager 이런걸로 하면 안되나&quot; 하여 불평.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: Consolas; font-size: 11pt;&quot;&gt;DefaultBatchConfigur,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: Consolas; font-size: 11pt;&quot;&gt;SimpleBatchConfiguration&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Bean을 상속받아서 열심히&amp;nbsp;getTransactionManager()를 열심히 오버라이딩 시도.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;오버라이딩 하며 한창 삽질하다, Error description 에서 BatchConfiguration을 내가 만든게 아니라, SimpleBatchConfiguration.class 만 보던것을 발견.&lt;/span&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;왜 그러지? 왜 왜 bean overriding이 안되지 고민 끝에&amp;nbsp;Error 내용 중에&amp;nbsp;Action 문구를 발견함.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;pre style=&quot;background-color: rgb(43, 43, 43);&quot;&gt;&lt;p&gt;&lt;font color=&quot;#a9b7c6&quot; face=&quot;Consolas&quot;&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;Action:
Consider renaming one of the beans or enabling overriding 
&lt;b&gt;by setting spring.main.allow-bean-definition-overriding=true&lt;/b&gt;&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp; &lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;5. 구글링해보니 Spring Boot 2.1 부터 사고를 방지하기 위하여&amp;nbsp;Bean Overriding이 기본 비활성화 됨. - &lt;/span&gt;&lt;a href=&quot;https://github.com/spring-projects/spring-booT/wiki/Spring-Boot-2.1-Release-Notes&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Spring Boot 2.1 Release Notes&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;h3 id=&quot;user-content-bean-overriding&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 24px; font-size: 1.25em; line-height: 1.25; color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;;&quot;&gt;Bean Overriding&lt;/h3&gt;&lt;p&gt;&lt;span style=&quot;color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;Bean overriding has been disabled by default to prevent a bean being accidentally overridden. If you are relying on overriding, you will need to set&lt;/span&gt;&lt;span style=&quot;color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;code style=&quot;color: rgb(36, 41, 46); box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;spring.main.allow-bean-definition-overriding&lt;/code&gt;&lt;span style=&quot;color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;code style=&quot;color: rgb(36, 41, 46); box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;true&lt;/code&gt;&lt;span style=&quot;color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;nbsp; &lt;span style=&quot;font-size: 11pt;&quot;&gt;6. Bean Overriding을 활성화 하기 위해 application.yml에&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: rgba(27, 31, 35, 0.05); color: rgb(36, 41, 46); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 11pt;&quot;&gt;spring.main.allow-bean-definition-overriding: true&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;옵션 추가.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp; 7. 파-워 해결.&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;결론&lt;/h2&gt;&lt;div&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Spring boot 2.1 부터는 bean definition overriding이 false인것을 기억하자.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;분명 이전에도 비슷한 문제를 겪었었는데....&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>SPRING</category>
      <category>2.1</category>
      <category>bean definition overriding</category>
      <category>spring Batch</category>
      <category>spring boot</category>
      <category>transaction manager</category>
      <category>스프링 부트</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/22</guid>
      <comments>https://bkim.tistory.com/22#entry22comment</comments>
      <pubDate>Tue, 12 Feb 2019 20:34:46 +0900</pubDate>
    </item>
    <item>
      <title>R3와 Corda의 탄생배경</title>
      <link>https://bkim.tistory.com/21</link>
      <description>&lt;p&gt;R3는 금융 서비스를 위해 설계된 엔터프라이즈 블록체인&amp;nbsp;플랫폼인 corda를 개발하고 서비스하는&amp;nbsp;소프트웨어 회사다. R3는 2014년 소규모의 가족 회사로 출발했는데 R3중 R은&amp;nbsp;CEO인&amp;nbsp;David Rutter의 성을 뜻하고, 3은 공동 설립자의 수를 뜻한다.&lt;/p&gt;&lt;p&gt;R3는 2014년 동안 암호화폐 회사들이 금융 기관들을 대체하고자 하는 시도를 계속해서 지켜봐왔고, 블록체인 기술이 금융시장에 가져올 혁신을 대응하기 위해 비트코인과 이더리움 등 성공적으로 동작하고 있는 블록체인에 대한 연구를 진행했다. 연구의 목적은 암호화폐 회사들의 공격에 대응하는 것도 있었지만,&amp;nbsp;블록체인을&amp;nbsp;금융시장에 어떻게 적용할지, 실무적인 측면에서 바라보고 금융시장에 적용할 수 있는 기존 블록체인 기술에 대한 리뷰와 선택을 진행하는 것도 포함되어 있었다.&lt;/p&gt;&lt;p&gt;R3는 2014부터 2015년까지 수차례의 컨퍼런스를 진행하면서 블록체인과 분산원장에 대한 차이점을 분명히 하는 최초의 논문인 CaaS(Consensus-as-a-Service)를 발표했고, FX 결제를 초함한 구체적인 금융 유즈케이스를 포함한 협의를 진행했다. 또한&amp;nbsp;다양한 은행과 블로체인 기업, 금융기관들이 함께하는 컨소시엄을 구성하게 되면서 2015년 11월 말 42개의 금융 기관이 참여하는&amp;nbsp;DLG(Distributed Ledger Group)를 발표하며 R3라는 이름을&amp;nbsp;대체하게 되었다.&lt;/p&gt;&lt;p&gt;IBM에서&amp;nbsp;하이퍼레저를 개발하던 Richard&amp;nbsp;Brown은 여러차례의 컨퍼런스와 대화를 통해&amp;nbsp;기존의 블록체인 플랫폼으로는 실 금융시장에 적용할 수 없다는 판단을 내렸고,&amp;nbsp;영국 버클레이 은행의 아키택트였던&amp;nbsp;James Carlyle, 비트코인 초기&amp;nbsp;개발자&amp;nbsp;Mike Hearn 등을 영입하여 Corda라는 새로운 금융 특화 블록체인 플랫폼을 개발하였고 2016년 1분기 말에 Corda라는 새로운 시스템을 구축하였다. 2016년 4월 5일 Richard는 Corda가 무엇인지, 설계 목표가 무엇진지, Corda는 블록체인이나 Cryptocurrency가 아니라 분산 원장이라는는 점에 대해 처음으로 공개적으로 설명했다. (Corda의 블록체인에 대한 기술적 정의는 다음편에 다루는 것으로...)&amp;nbsp;&lt;/p&gt;&lt;p&gt;기존의 비트코인, 이더리움, 리플과 같은 블록체인 플랫폼을&amp;nbsp;실 금융시장에 적용할 수 없었던&amp;nbsp;이유에 대하여 &lt;a href=&quot;https://brunch.co.kr/@jeffpaik/22&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;백종찬님의 글&lt;/a&gt;을 인용하였다.&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;1. 데이터 프라이버시&lt;/p&gt;&lt;p&gt;기존의 블록체인 구조는 네트워크 참여자가 모든 거래 내역을 보관하고 열람하는 구조다. 즉 A와 B간의 거래를 C가 검증해야한다. 고객 또는 자산의 기밀성을 보호해야 하는 금융산업에서 이와 같은 공개적인 데이터 검증 구조는 적용될 수 없다.&lt;/p&gt;&lt;p&gt;2. 확장성&lt;/p&gt;&lt;p&gt;모든 네트워크 참여자가 거래에 대한 합의를 도출하고 검증을 하게 되면 참여자가 많아질수록 거래 처리의 속도가 느려진다. 업계에서 주로 &quot;초당 거래수&quot;라고 얘기하는데, 빠른 속도가 생경인 긍융거래에서 이러한 확장성의 한계는 큰 문제다.&lt;/p&gt;&lt;p&gt;3. 법률적 책임&lt;/p&gt;&lt;p&gt;스마트계약의 경우 기존의 블록체인은 법률적 책임의 소재가 불분명하다. 컴퓨터 코드에 의한 비가역적인 실행은 가능하지만 실제로 그것이 법률적 강제성을 가지는 것은 아니다.&lt;/p&gt;&lt;p&gt;4. 개연적 결제 완결성&lt;/p&gt;&lt;p&gt;기존의 블록체인, 특히 비트코인이나 이더리움과 같은 퍼블릭 블록체인의 경우, 결제의 완결성을 법률 또 기술적으로 100% 보장하지 않는다. 항상 네트워크의 포크 또는 블록 재종에 등의 가능성이 존재한다. 은행거래의 경우 결제의 완결성은 중앙은행이 법적으로 보장하기 때문에 법률적인 특면에서도 문제가 있다.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;2017년 R3 컨소시엄은 공식적으로 두 그룹으로 나누었다. 한 그룹은 Corda 플랫폼 구축에 중점을 두고 있으며, 다른 하나는 컨소시엄 멤버에게 적절한 서비스를 제공하는데 중점을 두는&amp;nbsp;연구 그룹이다. 연구팀은 40개가 넘는 프로젝트를 진행중이며 20개 이상의 프로젝트를 완료했다. 그들이 진행하는 프로젝트들은 모두&amp;nbsp;이더리움, 리블, 패브릭, 코다, 캐나다 중앙은행, 바클레이즈 은행 등 블록체인에 국한되지 않은,&amp;nbsp;다양한 플랫폼과 관련되어 있다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;R3 컨소시엄의 프로젝트 중 하나인&amp;nbsp;제네시스 프로젝트는 42개 금융사들이 블록체인 위에서 기업어음을 보내는 프로젝트를 진행했고 그 이후에도 60개가 넘는 다양한 프로젝트에 은행들이 자발적으로 참여하여 매우 빠른 발전을 이루었다. 또한 국내 사례로 2017년 5월 국내 은행 중 국민,신한,우리,하나,기업은행 등 5개 시중은행이 R와 함께 고객확인 정보를 블록체인으로 저장,관리하는 프로젝트를 성공한 바 있다. 다만 금융사들의 고객정보를 공유하는 행위 등 법적으로 금지되어 있는 문제가 있기 때문에 상용화까지 처리해야할 이슈가 있을것으로 보인다.&lt;/p&gt;&lt;p&gt;지금까지 R3와 Corda의 탄생 배경과 발전 과정을 알아보았다. 다음 글에서는 Corda의 기술적 바탕을 좀 더 살펴보고 기존의 블록체인과 다른점은 무엇인지,&amp;nbsp;엔터프라이즈 플랫폼으로서 하이퍼레져와 차이점은 무엇인지 등 기술적인 부분을&amp;nbsp;좀 더 살펴 보고 Corda에 대한 이해도를 높이고자 한다.&lt;/p&gt;&lt;p&gt;참조&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.ofnumbers.com/2017/02/27/a-brief-history-of-r3-the-distributed-ledger-group/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;A brief history of R3 – the Distributed Ledger Group&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://gendal.me/2017/02/21/the-corda-way-of-thinking/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;THE CORDA WAY OF THINKING&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://brunch.co.kr/@jeffpaik/22&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;R3, 넌 도데체 누구냐!&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <category>BLOCKCHAIN</category>
      <category>blockchain</category>
      <category>corda</category>
      <category>r3</category>
      <category>블럭체인</category>
      <category>코다</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/21</guid>
      <comments>https://bkim.tistory.com/21#entry21comment</comments>
      <pubDate>Sun, 13 Jan 2019 18:02:33 +0900</pubDate>
    </item>
    <item>
      <title>모바일 청첩장 공개 (Parallax scrolling, skrollr.js)</title>
      <link>https://bkim.tistory.com/19</link>
      <description>&lt;h3&gt;개요&lt;/h3&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;결혼을 하게 되어 모바일 청첩장을 직접 만들기로 했다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;기획자가 확실하신 분이라 그분의 니즈를 만족시키기&amp;nbsp;위한 템플릿을 찾을 수 없었다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;기획자님은 선과 원이 만나 우리가 된다는 것을 강조하길 원하셨고&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;나는 스크롤을 내리면 화면의 구성을 변경할 수 있는&amp;nbsp;parallax scrolling라는 기술로 개발하기로&amp;nbsp;했다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;Parallax scrolling를 위한 라이브러리는&amp;nbsp;&lt;a href=&quot;https://github.com/Prinzhorn/skrollr&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;skrollr&lt;/a&gt;.js 를 사용했다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;개발&lt;/h3&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;최대한 단순화 하기 위해서 index.html 안에 css와 js 모두 인라인으로 개발했다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;jquery, skrollr 두개의 라이브러리를 사용했고, 이미지는 상대경로로 설정해서, 사용하고자 하는 분은 이미지만 바꾸면 된다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;나는 AWS S3에 public 저장소를 하나 생성하고, FrontCloud CDN 을 연결해서 하객들에게 공유했다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;사용자 환경은 모바일에 최적화 했고, PC화면에서 보아도 깨지지 않도록 살짝 설정해 두었다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;청첩장을 직접 만드시는 분들께 도움이 될 수 있길 바라며 포스팅한다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;데모&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;a href=&quot;https://s3.ap-northeast-2.amazonaws.com/wedding-github/index.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://s3.ap-northeast-2.amazonaws.com/wedding-github/index.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;깃헙&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/wantutopia/mobileWeddingTemplate&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://github.com/wantutopia/mobileWeddingTemplate&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;스크린샷&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 437px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B8D1355BDC15DF25&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B8D1355BDC15DF25&quot; width=&quot;437&quot; height=&quot;649&quot; filename=&quot;녹화_2018_11_02_18_14_40_185.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>WEB</category>
      <category>Invitation</category>
      <category>mobile</category>
      <category>Parallax scrolling</category>
      <category>skrollr</category>
      <category>모바일</category>
      <category>청첩장</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/19</guid>
      <comments>https://bkim.tistory.com/19#entry19comment</comments>
      <pubDate>Fri, 2 Nov 2018 18:19:55 +0900</pubDate>
    </item>
    <item>
      <title>중앙 거래소 호가 매칭 알고리즘 설계</title>
      <link>https://bkim.tistory.com/18</link>
      <description>&lt;h3&gt;개요&lt;/h3&gt;&lt;p&gt;호가창 무결성을 보장하고 트랜잭션을 쉽게 관리하기위해서&amp;nbsp;&lt;a href=&quot;https://bkim.tistory.com/17?category=764864&quot;&gt;&lt;span style=&quot;color: rgb(9, 0, 255);&quot;&gt; RDB를 이용한 구현을 찾아봤다.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;하지만 RDB를 이용한 구현은 수평적으로 확장이 어렵기 때문에 IO를 담당할 하나의 MASTER DB에 의존성이 매우 높다.&lt;/p&gt;&lt;p&gt;또한 물리적 성능 향상을 위해서는 더 좋은 장비를 구매해야하고 단일장비의 성능엔 한계가 존재한다. (물리적으로나 비용적으로나)&lt;/p&gt;&lt;p&gt;그래서 호가 매칭 알고리즘에서 IO가 많이 발생하는 &lt;strong&gt;사용자 주문 생성, 주문 매칭 단계는 수평적 확장이&amp;nbsp; 쉬운 Redis를 사용&lt;/strong&gt;하여 처리하고&lt;/p&gt;&lt;p&gt;&lt;strong&gt;매칭된 주문 트랜잭션 생성 및 처리는 Mysql에서 관리&lt;/strong&gt;하는 방향으로 설계해 보았다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;Redis 살펴보기&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;레디스는 메모리 기반 저장소라서 클러스터 서버 전체 다운시 데이터가 날아간다??&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Redis가 Memory 기반 저장소라서 캐시 전용 저장소로 오해하는 부분이 많은데, Redis도 옵션에 따라 텍스트 형태의 파일로 데이터를 저장할 수 있다.&lt;br /&gt;때문에 클러스터가 전체 다운되어도 파일을 통해 데이터를 복구할 수 있다.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;트랜잭션 관리가 어렵다??&lt;ol&gt;&lt;li&gt;레디스는 싱글 쓰레드 기반이라 트랜잭션 관리가 쉬운편이다.&lt;br /&gt;또한 &lt;a href=&quot;https://redis.io/commands/eval&quot;&gt;Lua Script&lt;/a&gt; 를 사용하거나 &lt;a href=&quot;https://redis.io/topics/transactions&quot;&gt;트랜잭션&lt;/a&gt;을 지원하는 명령어 (MULTI) 를 통해서 트랜잭션을 보장할 수 있다.&lt;/li&gt;&lt;li&gt;오히려 싱글 쓰레드라 대량 작업시 블럭되는 점을 조심해야 한다. (keys 명령어나, 대용량 삭제와 같은 작업을 조심해야한다.)&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;대용량 데이터 저장이 어렵다??&lt;ol&gt;&lt;li&gt;하나의 Key 당 최대 512MB까지 저장가능하다. 적지않은 사이즈지만 히스토리 정보까지 모두 메모리에 올려두기엔 부담스러운게 사실이다.&lt;br /&gt;그래서 IO 관련 데이터들만 redis에 저장하고 거래/히스토리 데이터는 RDB에서 관리하는 방향으로 설계해야한다.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;클러스터링을 지원하여 가용성이 높다?&lt;ol&gt;&lt;li&gt;Redis를 사용하는 가장 큰 이유이기도하지만 가장 조심해야할 부분이기도 하다.&lt;br /&gt;클러스터 구성에 따라 다르지만 보통 레디스 클러스터는 Master - Slave 구조로 구성된다. &lt;br /&gt;Master가 다운될 시 Slave가 자동으로 Master로 승격되는데 이때 승격될 Slave 에 데이터가 비어있으면 모든 클러스터의 데이터가 비워지게 된다.&lt;br /&gt;우리는 Redis 클러스터를 직접 구현하지않고 AWS 를 사용할거라 다행이다 ^^&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;설계&lt;/h3&gt;&lt;ol&gt;&lt;h4&gt;필요한 자료구조&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;주문 상황판 &lt;br /&gt;(buy/sell 주문의 order price 별로 order quantity 를 가지는 Sorted Set&amp;lt;score, orderSum&amp;gt;)&lt;br /&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px; margin-right: 10px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E1084D5BD0208025&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E1084D5BD0208025&quot; width=&quot;900&quot; height=&quot;403&quot; filename=&quot;1.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;margin-right: 10px;&quot;/&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;주문 리스트&lt;br /&gt;(Map&amp;lt;typeAndCoinAndPrice, List&amp;lt;order&amp;gt;&amp;gt; buyList, Map&amp;lt;typeAndCoinAndPrice, List&amp;lt;order&amp;gt;&amp;gt; sellList )&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px; margin-right: 10px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994047345BD020D612&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994047345BD020D612&quot; width=&quot;900&quot; height=&quot;539&quot; filename=&quot;2.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;margin-right: 10px;&quot;/&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;내 주문 &lt;br /&gt;(내 주문 상태를 관리하고 목록을 확인할 수 있는 Map&amp;lt;memberNo, Map&amp;lt;orderId, order&amp;gt;&amp;gt;)&lt;br /&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999BAA345BD020F70E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999BAA345BD020F70E&quot; width=&quot;900&quot; height=&quot;667&quot; filename=&quot;3.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div style=&quot;text-align: left;&quot;&gt;매칭된 두개의 Order 를 저장/처리할 Transaction RDB 테이블&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/ol&gt;&lt;p&gt;&lt;h3&gt;동작 시나리오&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;주문생성 (Create)&lt;/strong&gt;&amp;nbsp; - (주문 생성 전 주문이 필요로하는 코인/현금만큼 사용자의 잔고를 freeze 해야한다.)&lt;ol&gt;&lt;li&gt;새로운 주문이 들어오면 시퀀스 시작.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;(redis 트랜잭션 시작)&lt;/span&gt; &lt;br /&gt;'주문 상황판'을보고 매칭할 주문 리스트 진입점을 찾는다. &lt;strong&gt;(매칭되는 진입점이 없으면 v 단계로 이동)&lt;/strong&gt;&lt;ol&gt;&lt;li&gt;주문 타입이 Buy면 주문 가격이하의 Sell List중 가장 저렴한 리스트를 찾는다.&lt;/li&gt;&lt;li&gt;주문 타입이 Sell이면 주문 가격 이상의 Buy List중 가장 비싼 리스트를 찾는&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;매칭되는 리스트가 있으면 LPOP으로 order를 꺼내오고, '주문 상황판'과 '내 주문'에서 해당 order를 제거한다.&amp;nbsp;&lt;/li&gt;&lt;li&gt;요청 들어온 주문과 매칭된 주문의 거래량을 비교하여 분기 시퀀스를 따른다.&amp;nbsp;&lt;ol&gt;&lt;li&gt;IF (RequestOrder.quantity &amp;gt; MatchedOrder.quantity)면&amp;nbsp; 두개의 주문을 갖는 Transaction 객체를 생성하고,&lt;br /&gt;RequestOrder.quantity 를 차감한다.&amp;nbsp;&lt;br /&gt;처리된 MatchedOrder를 상황판과 사용자별 주문에 반영한다.&lt;br /&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;(redis 트랜잭션 커밋 후 다시 ii 단계부터 시작)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;ELSE IF (RequestOrder.quantity &amp;lt;= MatchedOrder.quantity) Matched Order을&amp;nbsp;RequestOrder.quantity 기준으로 분리한 후&lt;br /&gt;Transaction 객체를 추가하고, 분리된 여유분의 Order를&amp;nbsp; 다시 주문리스트로 LPUSH한다. (RequestOrder 의 주문량은 0이됨)&lt;br /&gt;스플릿되어 처리된 MatchedOrder를 상황판과 사용자별 주문에 반영한다.&lt;br /&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;(redis 트랜잭션 커밋후 vi 단계로 이동)&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;매칭되는 리스트가 없으면 Request Order의 가격 리스트에 RPUSH 하고 상황판과 내 주문에 반영한다.&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;(redis 트랜잭션 커밋)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;생성된 Transaction 객체들을 처리한다.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;주문 밸리데이션 (잔고, 요청내용 2중 검증)&lt;/li&gt;&lt;li&gt;사용자별 잔고 증감 및 수수료 취득&amp;nbsp;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;주문 관리 (Read)&lt;/strong&gt;&lt;ol&gt;&lt;li&gt;고객별 My 주문 리스트는 사용자 별 '내 주문' 모델을 통해 관리한다.&lt;/li&gt;&lt;li&gt;전체 주문량은 '주문 상환판' 모델을 통해 관리한다.&lt;/li&gt;&lt;li&gt;체결내역은 Transaction 테이블을 통해 관리한다.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;주문 수정 (Update)&lt;/strong&gt;&lt;ol&gt;&lt;li&gt;주문량/주문가 수정의 경우 &lt;br /&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;(redis 트랜잭션 시작)&lt;/span&gt;&lt;br /&gt;대상 주문을 리스트에서 POP 하여 값 수정 후 RPUSH&amp;nbsp;&lt;br /&gt;주문 상황판, 내 주문도 업데이트&lt;br /&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;(redis 트랜잭션 종료)&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주문 취소&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(Delete)&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;ol&gt;&lt;li&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주문 취소의 경우&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;(redis 트랜잭션 시작)&lt;/span&gt;&lt;br /&gt;대상 주문을 리스트에서 POP&lt;br /&gt;주문 상황판, 내 주문도 업데이트&lt;br /&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;(redis 트랜잭션 종료)&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;&lt;h4&gt;예외 처리&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;모든 주문은 요청 전에 검증(잔고확인, 소유자 확인, 권한 확인)을 통과해야한다.&lt;/li&gt;&lt;li&gt;검증된 주문이라도 트랜잭션 처리 전에 한번 더 검증한다.&lt;/li&gt;&lt;li&gt;주문처리 우선순위는 가격 &amp;gt; 시간이다.&lt;/li&gt;&lt;li&gt;트랜잭션 생성을 위해 주문을 LPOP 하여 거래량 차감 후 LPUSH 하는사이 시간 우선순위를 위배할 수 있다.&amp;nbsp; &amp;nbsp;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>BLOCKCHAIN</category>
      <category>거래소</category>
      <category>매칭</category>
      <category>알고리즘</category>
      <category>자료구조</category>
      <category>중앙 거래소</category>
      <category>호가</category>
      <category>호가 매칭 알고리즘</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/18</guid>
      <comments>https://bkim.tistory.com/18#entry18comment</comments>
      <pubDate>Wed, 24 Oct 2018 16:39:57 +0900</pubDate>
    </item>
    <item>
      <title>암호화폐 거래소 구축을 위한 주문 매칭 알고리즘 분석 #1</title>
      <link>https://bkim.tistory.com/17</link>
      <description>&lt;h3&gt;개요&lt;/h3&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;암호화폐 거래소를 구축하기 위해 주문(호가) 매칭 알고리즘을 찾아보던 중 좋은 글이 있어 번역과 사족을 달았다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/in/davidveksler&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;David Veksler&lt;/a&gt; 라는 소프트웨어 아키택트의 글이고, 설계한 암호화페 거래소를&amp;nbsp;중국 시장에 런칭까지 했다고 한다.&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;a href=&quot;http://automagical.rationalmind.net/2013/10/16/bitcoin-order-matching-algorithm/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;원문&lt;/a&gt;과 더불어 &lt;a href=&quot;https://wizardry.liberty.me/how-to-build-a-bitcoin-exchange-part-1-design-goals-risk-management/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;중국 시장 거래소 런칭에 관련된 글&lt;/a&gt;도&amp;nbsp;있으니 같이 보면 좋겠다.&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;번역은&amp;nbsp;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;녹색으로 표현하고&amp;nbsp;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;사족은 검은색으로 달았다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;h3&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;결론&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;아주 단순한 구조의 설계지만 꼼꼼히 살펴볼수록 튼튼해 보인다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;Buy/Sell 주문을 하나의 테이블에&amp;nbsp;넣기 때문에 RDB 저장소를 사용하여도 괜찮은 IO를 보장할 것같다. (사실 IO 성능이 아닌 확장성 문제 때문이긴 하지만 하나의 마스터DB와 슬레이브들로&amp;nbsp;어느정도 서비스 가능한 TPS를 보장해 줄 수 있을듯)&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;아래에 사족을 달았듯이 Order 의 Status 검증을 주문 요청 전에 진행한다면 트래픽을 분산시켜 성능 높일 수 있을것 같다.&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;테이블 구조도에서 Type 값들을 모두 정규화 했는데 반정규화해서 사용해도 무방해 보이고 (미약하나마 성능향상위해) OrderBook 과 Transaction 이 가지는 관계, 남은 거래량을 처리하는 방법이 단순하지만 명시적이라 좋은 방법이라 생각한다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;또한 매칭 모듈 시작 트리거를 고객이 주문한 시점으로만 제한하고있어서 개인적으로 모호했던 부분을 분명히 할 수 있어서 좋았다.&lt;/p&gt;&lt;h3&gt;본문&lt;/h3&gt;&lt;h4 style=&quot;margin-left: 2em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;비트코인 거래소 프로젝트 파트 2: 주문 매칭 알고리즘&lt;/span&gt;&lt;/h4&gt;&lt;h4 style=&quot;margin-left: 2em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;요약&lt;/span&gt;&lt;/h4&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;통화 거래소는 구매자와 판매자가 자신이 가진 통화를 서로 다른&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;통화 유형으로 교환 할 수 있는 시스템이다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;h4 style=&quot;margin-left: 2em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;본문&lt;/span&gt;&lt;/h4&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;주문 매칭 모듈은 구매/판매 주문을 매칭하고 거래를 만들어 거래의 흐름을 기록하고 고객들의 잔고를 업데이트 한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;트리거: 한명의 고객이 거래량과 가격을 입력하고&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;주문버튼(Buy 또는 Sell)&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;을&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;클릭 한다.&lt;/span&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33);&quot;&gt;본문에서는 액션으로 적혀있지만 트리거라고 이해하면 더 좋을것 같다. 이제부터 나오는 1~12번까지의 과정은 고객의 주문 트리거를 통해 실행된다.&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;1. 웹사이트는 고객의 Order를&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;Pending 상태로 OrderBook 이라는 테이블에 저장한다. 우선 주문을&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;처리하기 위해 쌓는다(filed).&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;그런 다음 오더 매칭 서비스는 Pending된 Order를 순차적으로 훑어본다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;em style=&quot;border: 0px; font-family: Lato, sans-serif; font-size: 16px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; color: rgb(43, 43, 43);&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;[public int PlaceBuyBid(int customerId, decimal quantityOfBTC, decimal pricePerBTC, DateTime ?expirationDate = null) ,&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;em style=&quot;border: 0px; font-family: Lato, sans-serif; font-size: 16px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; color: rgb(43, 43, 43);&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;public int PlaceSellOffer(int customerId, decimal quantityOfBTC, decimal pricePerBTC, DateTime ?expirationDate = null)]&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;2. 이 때 주문이 취소되었거나 만료되었는지를 확인하여 Order의 상태를 재검증 한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;3. order 마다 자금 검증을 하고, 고객은 order 가 필요로 하는 자금을 가지고 있어야만 해당 order의 상태룰&amp;nbsp;active로 변경한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;그렇지 않을 경우엔 suspended 되는데 고객이 이후에 자금을 입금하면 다시 활성화 한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;font color=&quot;#22741c&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;검증을 통과하면&amp;nbsp;&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;font color=&quot;#22741c&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;a: order 의 상태가 Active로 변경된다.&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;font color=&quot;#22741c&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;b: 비용 지불이 필요한 order면(&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;sell order를 뜻하는 듯&lt;/span&gt;)&amp;nbsp;Frozen Balance를 더한다. (고객이&amp;nbsp; 자신이 가진 자산보다 더 많은 주문생성을 못하게 하기 위함) -&amp;nbsp;&lt;/span&gt;&lt;/font&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;하지만 이 기능은 나중에 제거했다 - 우리는 Available balance보다 더 많은 주문 생성을 가능하게 했고 거래 전에 검증하는 쪽으로 방향을 바꾸었다.&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33);&quot;&gt;Order suspended 는 그냥 pending 상태로 둔다는 말 같다. 앞서 말한 트리거가 발동할때마다 잔고를 확인해서 pending 또는 active로 처리한다. 잔고 확인하는 부분이 특이한데, 잔고 확인없이 주문을 생성해줄 경우 고객입장에서 주문생성을&amp;nbsp;빠르게 진행할&amp;nbsp;수 있지만 어뷰징이 걱정되고, 그냥 주문 요청시 잔고 체크하여 걸러 내는게 더 좋을것 같다. David는 이걸로도 부족했는지&amp;nbsp;order 검증시에도 잔액 검증을 빼고 거래 시점에 검증하는 쪽으로 바꿨다고한다.&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;4. 주문 매칭 시스템은 buy와 sell order 를 매칭하기 위해 동작한다. 주문을 매칭하기위해 모든 Acitve 상태인 Order의 가격을 검색한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;* 만약 트리거 주문이 buy 이면 가격이 작거나 같은 주문을 찾는다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;* sell 이면 가격이 크거나 같은 주문을 찾는다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;* 시장가의 sell 이면 가장 비싼 주문을, buy 만 가장 싼 주문을 찾는다.&lt;/span&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33);&quot;&gt;Order 인입시 검증을 해서 바로 Active 상태로 들여온 다음 1, 2, 3 과정을 생략하고 바로 4번으로 하는건 어떨까?&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33);&quot;&gt;pending -&amp;gt; active 대신 active -&amp;gt; pending 으로 상태변경 과정을 바꾸고 외부 배치 작업으로 order 의 pending -&amp;gt; active, expired 작 업을 진행하는것도 좋을것 같다&lt;/span&gt;.&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;우리는 buy order를 위해서 오름차순으로 매칭하고 sell order를 위해서 내림차순으로 매칭한다. 그럼 다음 가격이 매칭되면 시간순으로 정렬한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;em style=&quot;border: 0px; font-family: Lato, sans-serif; font-size: 16px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; color: rgb(43, 43, 43);&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;[ISpecification IsMatchingOrderQuery(decimal price, int orderTypeId, int wantAssetTypeId,int offerAssetTypeId, bool? isMarketOrder)]&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;5. 우리는 상위 3개의 매치들을 메모리로 불러온다. 3개까지 가져오는 이유는 매칭된 주문들이 추후 검증에서 실패할 수 있기 때문이다.&lt;/span&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33);&quot;&gt;메모리로 불러온다는 말은 단순히 DB에서 시스템상으로 SELECT 해온다는 말 같다.&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;6. 우리는 order 와 match를 비교한다. 이것은 C#은 이용한 이중 검증이다. - Order가 이전 데이터베이스 쿼리 결과와 일치해야한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;order는 다음 조건은 만족해야한다. ($/BTC, order types[buy/sell], non-two market orders, matching prices)&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0); font-family: Lato, sans-serif; font-size: 16px;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;border: 0px; font-family: Lato, sans-serif; font-size: 16px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; color: rgb(43, 43, 43);&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;[OrderComparisonResult CompareOrders(Order firstOrder, Order secondOrder)]&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33);&quot;&gt;쿼리로 매칭하는 주문들을 불러왔지만 시스템 상에서 다시 한번 검증한다는 말인&lt;/span&gt;&lt;span style=&quot;color: rgb(33, 33, 33);&quot;&gt;듯.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;7. 만약 order 비교가 성공하면 매칭됨을 기록(record)하는 transaction 을 만든다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0); font-family: Lato, sans-serif; font-size: 16px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;border: 0px; font-family: Lato, sans-serif; font-size: 16px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; color: rgb(43, 43, 43);&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;[Transaction GetTransactionForTwoOrders(OrderComparisonResult comparisonResult)]&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *&amp;nbsp;A_Order 는 buy order&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 8em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;* B_Order 는 sell order&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;(A와 B를 사용하는 이유는 아직 어떤 주문이 Buy/Sell 이 될지 확실하지 않기 때문이다.)&lt;/span&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33);&quot;&gt;Buy/Sell 두개의 오더를 가지는 하나의 Transaction 생성&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;font color=&quot;#212121&quot;&gt;Transaction 에 들어간 Order Status도 변경하는게 좋지 않을까?&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;8. 만약 주문간에&amp;nbsp;주문량이 정확히 일치하지 않으면 주문량이 남은 쪽 주문을 쪼개서 새로운 주문을 생성한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;9.&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;border: 0px; font-family: Lato, sans-serif; font-size: 16px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; color: rgb(43, 43, 43);&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;[ActivateTakeProfitAndStopLossOrders(Order order)]&lt;/span&gt;&lt;/em&gt;&lt;span style=&quot;color: rgb(71, 102, 0); font-family: Lato, sans-serif; font-size: 16px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;를 실행한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;TODO - 여기서 바로 시작하는게 아니라 스케쥴링한다. 자세한 내용은 다른 포스트 참고&lt;/span&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33);&quot;&gt;무슨내용인지 궁금한데 연결된 포스트가 없다 ㅠㅠ&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;10. 주문이 매칭된 거래 (Transaction)을 처리하고 결과를 기록(record)한다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;em style=&quot;border: 0px; font-family: Lato, sans-serif; font-size: 16px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; color: rgb(43, 43, 43);&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;[public Order ProcessTransaction(Transaction transaction)]&lt;/span&gt;&lt;/em&gt;&lt;span style=&quot;color: rgb(71, 102, 0); font-family: Lato, sans-serif; font-size: 16px;&quot;&gt;&amp;nbsp;(note: this module is a database transaction)&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;a: 거래와 쪼개진 주문을 DB에 추가한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 6em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;b: 거래에 포함된&amp;nbsp;두 주문 모두에게&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 8em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;* 인출 금액을 차감한다. (고객의 달러나 BTC 계좌에서)&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 8em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;* 신용자산을 더한다. (고객의 달러나 BTC 계좌에서))&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 8em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;* 수수료 계좌에 수수료를 기록(record)한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 8em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;* 동결 자산을 녹인다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 8em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;* 변경점들을 저장한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;11. 쪼개진 주문의 남은 거래량이 0이 될때까지 대상으로 과정을 반복하거나, 매칭되는 주문이 없을때까지 반복 한 뒤 해당 주문을 active 상태로 유지한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0); font-family: monospace, serif; font-size: 15px;&quot;&gt;foreach (OrderProcessResultModel n in ProcessOrder(splitOrder.OrderId))&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0); font-family: monospace, serif; font-size: 15px;&quot;&gt;{&lt;/span&gt;&lt;br style=&quot;color: rgb(43, 43, 43); font-family: monospace, serif; font-size: 15px;&quot;&gt;&lt;span style=&quot;color: rgb(43, 43, 43); font-family: monospace, serif; font-size: 15px;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;yield return n;&lt;/span&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(43, 43, 43); font-family: monospace, serif; font-size: 15px;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0); font-family: monospace, serif; font-size: 15px;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33); font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;거래량이 남았을경우 처리가 궁금했는데 단순하게 푼것 같다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(33, 33, 33); font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;필요한 거래량만큼 여러 주문을 불러와서 트랜잭션 진행하는것보다 직관적인 방법이지만&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0); font-family: monospace, serif; font-size: 15px;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt; color: rgb(33, 33, 33);&quot;&gt;시간 복잡도 N이 추가된다. 안정성이 중요하다면 이정도는 감수하는것도 좋을듯..&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;margin-left: 4em;&quot;&gt;&lt;span style=&quot;color: rgb(71, 102, 0);&quot;&gt;12. 만약 남은 거개량이 0이되면 status를 Completed 로 변경한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A900335B9B41E638&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A900335B9B41E638&quot; width=&quot;900&quot; height=&quot;592&quot; filename=&quot;OrderBook-Schema.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>BLOCKCHAIN</category>
      <category>bitcoin</category>
      <category>exchange</category>
      <category>order matching algorithm</category>
      <category>거래소</category>
      <category>매칭</category>
      <category>블럭체인</category>
      <category>비트코인</category>
      <category>알고리즘</category>
      <category>오더 매칭 알고리즘</category>
      <category>주문</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/17</guid>
      <comments>https://bkim.tistory.com/17#entry17comment</comments>
      <pubDate>Thu, 13 Sep 2018 18:56:35 +0900</pubDate>
    </item>
    <item>
      <title>Java Garbage Collection 요약</title>
      <link>https://bkim.tistory.com/16</link>
      <description>&lt;p&gt;Java로 몇년간 서버개발을 하고, 안드로이드 개발을 최근에 시작했다.&lt;/p&gt;
&lt;p&gt;그래도 자바 개발자인데 GC에 대해서 확실하게 설명할 수 있어야지! 하는 생각에 Java GC를 요약해본다.&lt;/p&gt;
&lt;p&gt;요약을 위한 포스트임으로 자세한 내용은 아래 참고를 확인 바란다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://d2.naver.com/helloworld/1329&quot;&gt;자바의 신 이상민님이 NAVER D2에 올리신 글&lt;/a&gt;과 '&lt;a href=&quot;http://book.daum.net/detail/book.do?bookid=BOK00028672331YE&quot;&gt;자바 고양이 Tomcat 이야기&lt;/a&gt;' 도서를 참고했다.&lt;/p&gt;
&lt;h2 id=&quot;garbage-collection&quot;&gt;Garbage Collection&lt;/h2&gt;
&lt;p&gt;GC는 Garbage Collection의 약자다. (Garbage Collector 아님ㅋ) Java는 Garbage Collector가 메모리 관리(Garbage Collection)를 자동으로 해주기 때문에 메모리 해제를 위한 별도의 코드가 필요없다. (Java 1.2부터 GC에 관여할 수 있는 클래스가 추가 됨) 하지만 GC에 대한 고민없이 Garbage Collector만 믿고 규모있는 어플리케이션을 서비스하면 어김없이 장애가 발생한다. 왜일까?&lt;/p&gt;
&lt;h2 id=&quot;stw-stop-the-world-&quot;&gt;STW (Stop-The-World)&lt;/h2&gt;
&lt;p&gt;Full GC가 발생하면 JVM은 어플리캐이션 실행을 멈추고 GC를 실행하는 쓰레드만 작동한다. 만약 웹서버에서 Full GC가 발생하면 서비스는 중단될 것이고 서비스가 중단 된 동안 각종 Time Out이 발생할 것이고 미뤄진 작업들이 누적되어 또 다른 Full GC를 발생시켜 장시간 장애가 발생 할 수 있다.&lt;/p&gt;
&lt;p&gt;메모리 공간(heap)을 늘리면 Full GC를 피할 수 있을까? 메모리공간을 늘리면 Full GC의 첫 수행 시점은 늦출 수 있겠다. 하지만 STW의 시간은 heap 크기에 비례하기 때문에 메모리 공간이 클수록 더 많은 시간과 노력이 필요하다. 때문에 Heap을 많이 할당하는 것이 반드시 좋은 것만은 아니다.&lt;/p&gt;
&lt;p&gt;어떤 GC알고리즘을 사용하더라도 Full GC와 STW는 발생한다. Full GC를 어떻게 제거할 것인가!? 하는 질문 보다 Full GC는 왜 발생하는가? 그리고 어떻게 피할것인가? 어떻게 최소화 할 것인가? 라는 질문에 초점을 맞춰 보자.&lt;/p&gt;
&lt;h2 id=&quot;garbage-collector&quot;&gt;Garbage Collector&lt;/h2&gt;
&lt;p&gt;Garbage Colletor는 두 가지 일을 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;힙(heap)내의 객체 중에서 garbage를 찾아낸다.&lt;/li&gt;
&lt;li&gt;찾아낸 garbage를 처리해서 heap의 메모리를 회수한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그리고 두 가지의 전제조건 아래에서 만들어졌다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다.&lt;/li&gt;
&lt;li&gt;오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이러한 전제조건 아래에서 garbage를 처리하기 위해 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%95%AB%EC%8A%A4%ED%8C%9F_(%EA%B0%80%EC%83%81_%EB%A8%B8%EC%8B%A0&quot;&gt;HotSpot Vm&lt;/a&gt;)에서는 2개의 물리적 공간을 만들었다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Young Generation 영역 : 새롭게 생성한 객체의 대부분이 이곳에 위치. 대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 대부분의 객체가 Young 영역에 생성되었다가 사라진다. 이 영역에서 객체가 사라질 때 Minor GC가 발생했다고 말한다.&lt;/li&gt;
&lt;li&gt;Old Generation 영역 : Minor GC이후에도 Young 역역에서 사라남은 객체가 여기로 복사 된다. 대부분 Young 영역보다 크게 할당하며, 크기가 큰 만큼 Young 영역보다 GC는 적게 발생한다. 이 영역에서 객체가 사라질 때 Major GC(혹은 Full GC)가 발생한다고 말한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993C60335A15107A09&quot; alt=&quot;&quot;&gt; Heap Area 구조 : &lt;a href=&quot;https://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java&quot;&gt;https://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;위 그림에는 Perm(Permanent Generation) 영역이 추가로 보이는데 이곳은 클래스 로더에 의해 로드되는 클래스, 메소드 등에 대한 메타정보가 저장되는 영역으로 어플리케이션이 아닌 JVM에 의해 사용된다. 리플렉션을 사용하여 동적으로 클래스가 로딩되는 경우에 사용되기도한다.&lt;/p&gt;
&lt;h2 id=&quot;young-generation-&quot;&gt;Young Generation 영역의 구성&lt;/h2&gt;
&lt;p&gt;위 그림을 보면 Young 영역은 Eden과 S0, S1영역으로 나누어져 있다. S는 Survivor를 뜻한다.&lt;/p&gt;
&lt;p&gt;Young 영역에서 객체 처리절차는 &lt;a href=&quot;http://d2.naver.com/helloworld/1329&quot;&gt;이상민님의 글&lt;/a&gt;을 그대로 인용하겠다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;새로 생성한 대부분의 객체는 Eden 영역에 위치한다.&lt;/li&gt;
&lt;li&gt;Eden 영역에서 GC가 한 번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동된다.&lt;/li&gt;
&lt;li&gt;Eden 영역에서 GC가 발생하면 이미 살아남은 객체가 존재하는 Survivor 영역으로 객체가 계속 쌓인다.&lt;/li&gt;
&lt;li&gt;하나의 Survivor 영역이 가득 차게 되면 그 중에서 살아남은 객체를 다른 Survivor 영역으로 이동한다. 그리고 가득 찬 Survivor 영역은 아무 데이터도 없는 상태로 된다.&lt;/li&gt;
&lt;li&gt;이 과정을 반복하다가 계속해서 살아남아 있는 객체는 Old 영역으로 이동하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 절차를 확인해 보면 알겠지만 Survivor 영역 중 하나는 반드시 비어 있는 상태로 남아 있어야 한다. 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 두 영역 모두 사용량이 0이라면 여러분의 시스템은 정상적인 상황이 아니라고 생각하면 된다.&lt;/p&gt;
&lt;p&gt;이렇게 Minor GC를 통해서 Old 영역까지 데이터가 쌓인 것을 간단히 나타내면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://d2.naver.com/content/images/2015/06/helloworld-1329-3.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;old-generation-gc&quot;&gt;Old Generation의 GC&lt;/h2&gt;
&lt;p&gt;Old 영역은 기본적으로 할당 된 메모리에 데이터가 가득 차면 GC를 실행한다. 기본적으로 Young와 Old 영역크기는 1:2의 비율을 가지기 때문에 Old Generation의 GC가 더 많은 시간을 소요한다.&lt;/p&gt;
&lt;p&gt;JDK버전이 올라가면서 GC를 위한 방식들이 추가되었다. GC의 방식은 Young 영역과 Old 역역 모두에 영향을 미치며 JDK7 기준으로 5가지 방식이 있다. (최근 JDK 8은 G1GC 방식을 Default로 한다.)&lt;/p&gt;
&lt;p&gt;5가지의 GC에 대한 설명도 &lt;a href=&quot;http://d2.naver.com/helloworld/1329&quot;&gt;이상민님의 글&lt;/a&gt;을 그대로 인용하겠다.&lt;br /&gt;다만 해당 이상민님의 글은 2011년에 작성되어서 G1GC방식의 안정성에 대해 걱정하고 있지만, 지금은 G1GC 안정화 과정을 마치고 대부분의 서비스에서 채택하고있다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Old 영역은 기본적으로 데이터가 가득 차면 GC를 실행한다. GC 방식에 따라서 처리 절차가 달라지므로, 어떤 GC 방식이 있는지 살펴보면 이해가 쉬울 것이다. GC 방식은 JDK 7을 기준으로 5가지 방식이 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serial GC&lt;/li&gt;
&lt;li&gt;Parallel GC&lt;/li&gt;
&lt;li&gt;Parallel Old GC(Parallel Compacting GC)&lt;/li&gt;
&lt;li&gt;Concurrent Mark &amp;amp; Sweep GC(이하 CMS)&lt;/li&gt;
&lt;li&gt;G1(Garbage First) GC&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 중에서 운영 서버에서 절대 사용하면 안 되는 방식이 Serial GC다. Serial GC는 데스크톱의 CPU 코어가 하나만 있을 때 사용하기 위해서 만든 방식이다. Serial GC를 사용하면 애플리케이션의 성능이 많이 떨어진다.&lt;/p&gt;
&lt;p&gt;그럼 각 GC 방식에 대해서 살펴보자.&lt;/p&gt;
&lt;h3 id=&quot;serial-gc-xx-useserialgc-&quot;&gt;Serial GC (-XX:+UseSerialGC)&lt;/h3&gt;
&lt;p&gt;Young 영역에서의 GC는 앞 절에서 설명한 방식을 사용한다. Old 영역의 GC는 mark-sweep-compact이라는 알고리즘을 사용한다. 이 알고리즘의 첫 단계는 Old 영역에 살아 있는 객체를 식별(Mark)하는 것이다. 그 다음에는 힙(heap)의 앞 부분부터 확인하여 살아 있는 것만 남긴다(Sweep). 마지막 단계에서는 각 객체들이 연속되게 쌓이도록 힙의 가장 앞 부분부터 채워서 객체가 존재하는 부분과 객체가 없는 부분으로 나눈다(Compaction).&lt;/p&gt;
&lt;p&gt;Serial GC는 적은 메모리와 CPU 코어 개수가 적을 때 적합한 방식이다.&lt;/p&gt;
&lt;h3 id=&quot;parallel-gc-xx-useparallelgc-&quot;&gt;Parallel GC (-XX:+UseParallelGC)&lt;/h3&gt;
&lt;p&gt;Parallel GC는 Serial GC와 기본적인 알고리즘은 같지다. 그러나 Serial GC는 GC를 처리하는 스레드가 하나인 것에 비해, Parallel GC는 GC를 처리하는 쓰레드가 여러 개이다. 그렇기 때문에 Serial GC보다 빠른게 객체를 처리할 수 있다. Parallel GC는 메모리가 충분하고 코어의 개수가 많을 때 유리하다. Parallel GC는 Throughput GC라고도 부른다.&lt;/p&gt;
&lt;p&gt;다음 그림은 Serial GC와 Parallel GC의 스레드를 비교한 그림이다.&lt;img src=&quot;http://d2.naver.com/content/images/2015/06/helloworld-1329-4.png&quot; alt=&quot;JavaGarbage4&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caption&quot;&gt;그림 4 Serial GC와 Parallel GC의 차이 (이미지 출처: &quot;Java Performance&quot;, p. 86)&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;parallel-old-gc-xx-useparalleloldgc-&quot;&gt;Parallel Old GC(-XX:+UseParallelOldGC)&lt;/h3&gt;
&lt;p&gt;Parallel Old GC는 JDK 5 update 6부터 제공한 GC 방식이다. 앞서 설명한 Parallel GC와 비교하여 Old 영역의 GC 알고리즘만 다르다. 이 방식은 Mark-Summary-Compaction 단계를 거친다. Summary 단계는 앞서 GC를 수행한 영역에 대해서 별도로 살아 있는 객체를 식별한다는 점에서 Mark-Sweep-Compaction 알고리즘의 Sweep 단계와 다르며, 약간 더 복잡한 단계를 거친다.&lt;/p&gt;
&lt;h3 id=&quot;cms-gc-xx-useconcmarksweepgc-&quot;&gt;CMS GC (-XX:+UseConcMarkSweepGC)&lt;/h3&gt;
&lt;p&gt;다음 그림은 Serial GC와 CMS GC의 절차를 비교한 그림이다. 그림에서 보듯이 CMS GC는 지금까지 설명한 GC 방식보다 더 복잡하다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://d2.naver.com/content/images/2015/06/helloworld-1329-5.png&quot; alt=&quot;JavaGarbage5&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caption&quot;&gt;그림 5 Serial GC와 CMS GC(&lt;a href=&quot;http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf&quot;&gt;이미지 출처&lt;/a&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;초기 Initial Mark 단계에서는 클래스 로더에서 가장 가까운 객체 중 살아 있는 객체만 찾는 것으로 끝낸다. 따라서, 멈추는 시간은 매우 짧다. 그리고 Concurrent Mark 단계에서는 방금 살아있다고 확인한 객체에서 참조하고 있는 객체들을 따라가면서 확인한다. 이 단계의 특징은 다른 스레드가 실행 중인 상태에서 동시에 진행된다는 것이다.&lt;/p&gt;
&lt;p&gt;그 다음 Remark 단계에서는 Concurrent Mark 단계에서 새로 추가되거나 참조가 끊긴 객체를 확인한다. 마지막으로 Concurrent Sweep 단계에서는 쓰레기를 정리하는 작업을 실행한다. 이 작업도 다른 스레드가 실행되고 있는 상황에서 진행한다.&lt;/p&gt;
&lt;p&gt;이러한 단계로 진행되는 GC 방식이기 때문에 stop-the-world 시간이 매우 짧다. 모든 애플리케이션의 응답 속도가 매우 중요할 때 CMS GC를 사용하며, Low Latency GC라고도 부른다.&lt;/p&gt;
&lt;p&gt;그런데 CMS GC는 stop-the-world 시간이 짧다는 장점에 반해 다음과 같은 단점이 존재한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;다른 GC 방식보다 메모리와 CPU를 더 많이 사용한다.&lt;/li&gt;
&lt;li&gt;Compaction 단계가 기본적으로 제공되지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;따라서, CMS GC를 사용할 때에는 신중히 검토한 후에 사용해야 한다. 그리고 조각난 메모리가 많아 Compaction 작업을 실행하면 다른 GC 방식의 stop-the-world 시간보다 stop-the-world 시간이 더 길기 때문에 Compaction 작업이 얼마나 자주, 오랫동안 수행되는지 확인해야 한다.&lt;/p&gt;
&lt;h3 id=&quot;g1-gc&quot;&gt;G1 GC&lt;/h3&gt;
&lt;p&gt;마지막으로 G1(Garbage First) GC에 대해서 알아보자. G1 GC를 이해하려면 지금까지의 Young 영역과 Old 영역에 대해서는 잊는 것이 좋다.&lt;/p&gt;
&lt;p&gt;다음 그림에서 보다시피, G1 GC는 바둑판의 각 영역에 객체를 할당하고 GC를 실행한다. 그러다가, 해당 영역이 꽉 차면 다른 영역에서 객체를 할당하고 GC를 실행한다. 즉, 지금까지 설명한 Young의 세가지 영역에서 데이터가 Old 영역으로 이동하는 단계가 사라진 GC 방식이라고 이해하면 된다. G1 GC는 장기적으로 말도 많고 탈도 많은 CMS GC를 대체하기 위해서 만들어 졌다.&lt;img src=&quot;http://d2.naver.com/content/images/2015/06/helloworld-1329-6.png&quot; alt=&quot;JavaGarbage6&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caption&quot;&gt;그림 6 G1 GC의 레이아웃(이미지 출처: &quot;The Garbage-First Garbage Collector&quot; (TS-5419), JavaOne 2008, p. 19)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;G1 GC의 가장 큰 장점은 성능이다. 지금까지 설명한 어떤 GC 방식보다도 빠르다. 하지만, JDK 6에서는 G1 GC를 early access라고 부르며 그냥 시험삼아 사용할 수만 있도록 한다. 그리고 JDK 7에서 정식으로 G1 GC를 포함하여 제공한다.&lt;/p&gt;
&lt;p&gt;그러나 JDK 7을 실서비스에서 사용하려면 많은 검증 기간(1년은 필요하다는 생각이다)을 거쳐야 할 것으로 보이기 때문에, G1 GC를 당장 사용하고 싶어도 더 기다리는 것이 좋다는 것이 개인적인 생각이다. JDK 6에서 G1 GC를 적용했다가 JVM Crash가 발생했다는 말도 몇 번 들었기에 더더욱 안정화될 때까지 기다리는 것이 좋겠다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;gc-&quot;&gt;GC 방식 보충&lt;/h2&gt;
&lt;h3 id=&quot;parallel-gc&quot;&gt;Parallel GC&lt;/h3&gt;
&lt;p&gt;이름처럼 여러 Thread를 동원해 GC를 처리한다. 정확히 말하면 Young Generation의 GC를 병렬 처리하는 것이며 Parallel Copy 알고리즘을 사용한다. Old Generation은 Serial GC와 같은 Mark-compact 알고리즘을 사용한다. 자바 1.5부터 Parallel Old GC가 소개 됐고, Old Generation도 병렬처리 하게 되었다.&lt;/p&gt;
&lt;h3 id=&quot;cms-gc&quot;&gt;CMS GC&lt;/h3&gt;
&lt;p&gt;Low Latency GC 혹은 Low Pause GC라고도 부른다. Old Generation GC시 발생하는 STW 시간을 최소화 하는는게 목적이어서 Old Generation 의 GC 알고리즘만 차이가 있다. Young Generation은 Serial GC나 Parallel GC와 같다.&lt;/p&gt;
&lt;h2&gt;GC를 줄이기 위한 JVM 튜닝&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://d2.naver.com/helloworld/37111&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://d2.naver.com/helloworld/37111&lt;/a&gt; 이곳 만한곳이 없다. 하하하!&lt;/p&gt;&lt;p&gt;정리/요약으로 JVM 튜닝작업을 내것으로 만들기는 어려울 것 같다.&lt;/p&gt;&lt;p&gt;GC에 대하여 요약한 내용을 바탕으로 서비스를 해보고 직접 헤딩해보는게 최선일 듯!&amp;nbsp;&lt;/p&gt;&lt;p&gt;헤딩하게 되면 그 내용을 추가하겠다.&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>garbage collection</category>
      <category>GC</category>
      <category>Java</category>
      <category>JAVA GC</category>
      <category>가비지컬렌션</category>
      <category>자바</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/16</guid>
      <comments>https://bkim.tistory.com/16#entry16comment</comments>
      <pubDate>Wed, 22 Nov 2017 12:45:41 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 빌드 서버 구축하기 - Centos7, Jenkins, Sdkmanager</title>
      <link>https://bkim.tistory.com/15</link>
      <description>&lt;P&gt;안드로이드 빌드 서버를&amp;nbsp;구성하면서 메모한 내용을 정리한다.&lt;/P&gt;
&lt;P&gt;빌드환경은&amp;nbsp;&amp;nbsp;CentOS7, Jenkins, Github, Sdkmanager 로 구성하였다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;안드로이드 25 버전부터는 GLIBC_2.14&amp;nbsp;를 사용하기 때문에 CentOS 6이 아닌 7을 사용해야한다.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;CentOS 6에도 GLIBC_2.14를 설치할 수 있지만,&amp;nbsp;커널쪽 라이브러리를 수정하는건 부담이다. 피하자.&lt;/P&gt;
&lt;H2&gt;안드로이드 SDK설치&lt;/H2&gt;
&lt;P&gt;안드로이드 SDK설치 과정이 바뀌었다.&amp;nbsp;포스트를&amp;nbsp;쓰게 된 가장 큰 이유다.&lt;/P&gt;
&lt;P&gt;안드로이드 빌드환경 구성 방법을 구글링 해보면 adnroid-sdk r24.4.1&amp;nbsp;압축파일을 다운받아 SDK를 설정하는 방법이 대부분이다.&lt;/P&gt;
&lt;P&gt;여기서는 최신버전 SDK로&amp;nbsp;빌드하기 위해, 안드로이드 공식 홈에 나와있는 sdkmanager를 사용했다.&lt;br /&gt;&lt;/P&gt;
&lt;H4&gt;sdkmanger 설치 &amp;amp; 경로 설정&lt;/H4&gt;
&lt;P&gt;android 폴더를 만들어 sdkmanger를 다운 받는다.&lt;/P&gt;
&lt;P&gt;sdkmanger의 bin 폴더를&amp;nbsp;PATH에 추가 후&amp;nbsp;sdkmanger --list 명령어로 테스트 해본다.&lt;/P&gt;
&lt;P&gt;안드로이드 패키지 리스트가 나오면 설치완료.&lt;/P&gt;&lt;PRE style=&quot;FONT-SIZE: 9pt; FONT-FAMILY: '굴림체'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;mkdir android&lt;br /&gt;cd android&lt;br /&gt;wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip&lt;br /&gt;unzip sdk-tools-linux-3859397.zip&lt;br /&gt;rm sdk-tools-linux-3859397.zip&lt;br /&gt;PATH=$PATH:/절대경로/android/tools/bin&lt;br /&gt;sdkmanager --list&lt;/PRE&gt;
&lt;H4&gt;sdkmanger로 sdk 다운로드&amp;nbsp;&lt;/H4&gt;
&lt;P&gt;아까 생성한 android 폴더에서 platform-tools와 android-25, 26 platform을 설치한다.&lt;/P&gt;
&lt;P&gt;설치가 완료되면 몇몇 폴더들이 추가되어있다.&lt;/P&gt;
&lt;P&gt;지금의 android 폴더가 ANDROID_HOME이니 경로를 기억해두자.&lt;/P&gt;&lt;PRE style=&quot;FONT-SIZE: 9pt; FONT-FAMILY: '굴림체'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;sdkmanager &quot;platform-tools&quot; &quot;platforms;android-25&quot; &quot;platforms;android-26&quot;&lt;/PRE&gt;
&lt;H2&gt;&lt;PRE style=&quot;FONT-SIZE: 9pt; FONT-FAMILY: '굴림체'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;[bkim@server android]$ ls&lt;br /&gt;build-tools  licenses  output  platforms  platform-tools  tools&lt;/PRE&gt;&lt;/H2&gt;
&lt;H2&gt;깃 설치&lt;/H2&gt;
&lt;P&gt;깃허브에서 안드로이드 프로젝트 소스를 받아올것이다. 젠킨스 세팅 전에 git을 설치하자.&lt;/P&gt;
&lt;P&gt;설치 후 git 명령어를 날려보면 깃 명령어 리스트가 보인다.&lt;/P&gt;&lt;PRE style=&quot;FONT-SIZE: 9pt; FONT-FAMILY: '굴림체'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;yum update&lt;br /&gt;yum install git&lt;br /&gt;git&lt;/PRE&gt;
&lt;H2&gt;젠킨스 세팅&lt;/H2&gt;
&lt;H4&gt;젠킨스 설치&lt;/H4&gt;
&lt;P&gt;젠킨스 설치 과정은 따로 설명하지 않겠다. jar 파일을 다운받아 바로 실행하는 방법도 좋고, tomcat으로 띄우는 방법도 좋다.&lt;/P&gt;
&lt;P&gt;&lt;A class=tx-link href=&quot;https://pkg.jenkins.io/redhat/&quot; target=_blank&gt;젠킨스 공식 사이트&lt;/A&gt;를 참고하면 최신버전을 설치 할 수 있다.&lt;/P&gt;
&lt;H4&gt;환경변수 설정&lt;/H4&gt;
&lt;P&gt;ANDROID_HOME을 설정하자. 젠킨스는 편리하게 환경변수를 추가할 수&amp;nbsp;있는 메뉴를&amp;nbsp;제공한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;왼쪽 메뉴 중 Jenkins 관리 -&amp;gt; 시스템 설정 -&amp;gt; Global properties에&amp;nbsp;추가 -&amp;gt; 이름 ANDROID_HOME -&amp;gt; 값 아까 SDK 설치 경로 (/절대경로/android)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9947F43359B8D24915&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9947F43359B8D24915&quot; width=&quot;900&quot; height=&quot;139&quot; filename=&quot;5.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;H4&gt;플러그인 설치&lt;/H4&gt;
&lt;P&gt;github 연동을 위하여 git 관련 플러그인들을 설치해주자.&lt;/P&gt;
&lt;P&gt;왼쪽 메뉴 중 Jenkins 관리 -&amp;gt; 플러그인 관리 -&amp;gt; 설치가능 -&amp;gt; git plugin, github plugin 설치&lt;/P&gt;
&lt;P&gt;(gradle이 설치되어있지않으면&amp;nbsp;gradle 플러그인도 추가하자)&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 889px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990A633359B8CC6C30&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990A633359B8CC6C30&quot; width=&quot;889&quot; height=&quot;432&quot; filename=&quot;1.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;H4&gt;빌드 테스크설정&lt;/H4&gt;
&lt;P&gt;빌드 테스크 설정을 위해 새로운 Item을 추가하자.&lt;/P&gt;
&lt;P&gt;왼쪽 메뉴 중 새로운 Item -&amp;gt; Item 이름입력 -&amp;gt; Freestyle project 선택 -&amp;gt; OK&lt;/P&gt;
&lt;P&gt;아이템이 생성되었으면, 아이템 설정을 해주자. 단순 빌드를 위한 설정은 단순하다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;소스 코드 관리 탭 -&amp;gt; git 선택 -&amp;gt; Repository 주소 입력 -&amp;gt; 깃헙 계정 입력 (나는 서버에 깃헙 키를 등록해두어서 따로 사용자 연동을 하진 않았다)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F5443359B8CDDF16&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F5443359B8CDDF16&quot; width=&quot;900&quot; height=&quot;353&quot; filename=&quot;2.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;빌드 탭 -&amp;gt; Use Gradle Wrapper 선택 -&amp;gt; Make gradlew executable 체크 -&amp;gt; Tasks 에 clean assembleDebug 입력 (gradle 명령어는 각자에 맞게 수정)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9956933359B8CE4B17&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9956933359B8CE4B17&quot; width=&quot;900&quot; height=&quot;224&quot; filename=&quot;3.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;빌드 후 조치 탭 -&amp;gt; 빌드 후 조치 추가에서 Archive the artifacts 선택 -&amp;gt; Files to archive에 빌드 완료시 apk 결과물이 떨어지는 경로 입력 (따로 세팅 안했으면 app/build/outputs/apk/*.apk 로 입력하면 된다.)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9968383359B8D14E18&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9968383359B8D14E18&quot; width=&quot;900&quot; height=&quot;121&quot; filename=&quot;4.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;빌드 후 조치에서 Jenkins 저장 이외에 메일로 apk를 보내준다던지, 배포서비스로 apk를 전달하는 것 같은 태스크를 추가 할 수 있다.&lt;/P&gt;
&lt;P&gt;또한 빌드 유발 탭에서 깃헙 push 할때마다 빌드도록 세팅해두고, 빌드 후 조치 탭에서 빌드 결과를 메일이나 메신저로 전달하면... 좋다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;설정 저장 -&amp;gt; Build Now 클릭 -&amp;gt; 빌드 결과로 들어가면 빌드된 이미지를 확인할 수 있다&lt;/STRONG&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994BE23359B8D36634&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994BE23359B8D36634&quot; width=&quot;900&quot; height=&quot;282&quot; filename=&quot;6.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;H2&gt;마치며&lt;/H2&gt;
&lt;P&gt;젠킨스를 이용해서 안드로이드 빌드 서버를&amp;nbsp;구성했다. &lt;/P&gt;
&lt;P&gt;빌드 서버를 구성하는 이유는 대부분 CI 환경을 만들기 위함일 것이다.&lt;/P&gt;
&lt;P&gt;이제 젠킨스에 Findbugs 같은 코드 분석툴을 붙이고, 그래들 스크립트로 테스트 검증도 할 수 있다.&lt;/P&gt;
&lt;P&gt;Deploy Gate라는 서비스를 이용하면 apk를 배포하고, 무선으로 테스트폰에 설치까지 해준다고한다.&lt;/P&gt;
&lt;P&gt;결국에는 편하자고 하는 일들이니 우리들 모두 화이팅!!!&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 2em&quot;&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&lt;/P&gt;</description>
      <category>ANDROID</category>
      <category>Android</category>
      <category>build server</category>
      <category>CI</category>
      <category>jenkins</category>
      <category>sdkmanager</category>
      <category>sentos</category>
      <category>빌드</category>
      <category>안드로이드</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/15</guid>
      <comments>https://bkim.tistory.com/15#entry15comment</comments>
      <pubDate>Wed, 13 Sep 2017 14:07:42 +0900</pubDate>
    </item>
    <item>
      <title>Maven vs Gradle</title>
      <link>https://bkim.tistory.com/13</link>
      <description>&lt;H2&gt;Maven vs Gradle&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;스프링 기반의&amp;nbsp;프로젝트를 시작하면서&amp;nbsp;Maven을 처음 접했다. &lt;/P&gt;
&lt;P&gt;Ant를 사용한적도 없었고 의존성 관리와 빌드 스크립트에 대한 지식도 없었기에 이런게 있나보다 하고 사용했었다.&lt;/P&gt;
&lt;P&gt;Maven 책을 한권&amp;nbsp;보고나서야 프로젝트 구성, 빌드툴이 무었인지 이해할 수 있었고, 편리한 의존성 관리에 감사하며 부족함을 느끼지 못했다.&lt;/P&gt;
&lt;P&gt;하지만 프로젝트의 단위가 커지면서 빌드와 테스트에 소요되는 시간이 길어졌고, &lt;/P&gt;
&lt;P&gt;여러 모듈에서 설정을 상속받기 시작하면서 Gradle이라는 녀석이 계속 눈에 뛰었다. &lt;/P&gt;
&lt;P&gt;Gradle이 Maven의 단점을 보완해주고&amp;nbsp;사용해본 사람들이 좋다고들 하니&amp;nbsp;Maven이랑 비교해서 얼마나 좋은지 알아보려 한다.&lt;/P&gt;&lt;/DIV&gt;
&lt;H2&gt;&lt;A class=tx-link href=&quot;https://maven.apache.org/index.html&quot; target=_blank&gt;Maven&lt;/A&gt;&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;Apache의 이름 아래 2004년 출시&lt;/P&gt;
&lt;P&gt;Ant를 사용하던 개발자들의 불편함을 해소 + 부가기능 추가&lt;/P&gt;
&lt;P&gt;&lt;A class=tx-link href=&quot;https://maven.apache.org/what-is-maven.html&quot; target=_blank&gt;Maven은 무엇인가?&lt;/A&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;빌드를 쉽게 (Making the build process easy)&lt;/LI&gt;
&lt;LI&gt;pom.xml을 이용한 정형화된 빌드 시스템 (Providing a uniform build system)&lt;/LI&gt;
&lt;LI&gt;뛰어난&amp;nbsp;프로젝트 정보 제공&amp;nbsp;(Providing quality project information_&lt;/LI&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;Change log document created directly from source control&lt;/LI&gt;
&lt;LI&gt;Cross referenced sources&lt;/LI&gt;
&lt;LI&gt;Mailing lists&lt;/LI&gt;
&lt;LI&gt;Dependency list&lt;/LI&gt;
&lt;LI&gt;Unit test reports including coverage&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;개발 가이드 라인 제공 (Providing guidelines for best practices development)&lt;/LI&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;Keeping your test source code in a separate, but parallel source tree&lt;/LI&gt;
&lt;LI&gt;Using test case naming conventions to locate and execute tests&lt;/LI&gt;
&lt;LI&gt;Have test cases setup their environment and don’t rely on customizing the build for test preparation.&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;새로운 기능을 쉽게 설치할 수 있고 업데이트할 수 있음&amp;nbsp;(Allowing transparent migration to new features)&lt;/LI&gt;&lt;/UL&gt;&lt;/DIV&gt;
&lt;H2&gt;&lt;A class=tx-link href=&quot;https://gradle.org/&quot; target=_blank&gt;Gradle&lt;/A&gt;&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;Ant와 Maven의 장점을 모아모아 2012년 출시&lt;/P&gt;
&lt;P&gt;Android OS의 빌드 도구로 채택 됨&lt;/P&gt;
&lt;P&gt;&lt;A class=tx-link href=&quot;https://docs.gradle.org/4.0/userguide/introduction.html&quot; target=_blank&gt;Gradle이란 무엇인가?&lt;/A&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;Ant처럼&amp;nbsp;유연한 범용 빌드 도구&amp;nbsp;(A very flexible general purpose build tool like Ant.)&lt;/LI&gt;
&lt;LI&gt;Maven을 사용할 수 있는 변환 가능 컨벤션 프레임 워크&amp;nbsp;(Switchable, build-by-convention frameworks a la Maven. But we never lock you in!)&lt;/LI&gt;
&lt;LI&gt;멀티 프로젝트에 사용하기 좋음&amp;nbsp;(Very powerful support for multi-project builds.)&lt;/LI&gt;
&lt;LI&gt;Apache Ivy에 기반한 강력한 의존성 관리&amp;nbsp;(Very powerful dependency management (based on Apache Ivy))&lt;/LI&gt;
&lt;LI&gt;Maven과 Ivy 레파지토리 완전 지원&amp;nbsp;(Full support for your existing Maven or Ivy repository infrastructure.)&lt;/LI&gt;
&lt;LI&gt;원격 저장소나, pom, ivy 파일 없이 연결되는 의존성 관리 지원 &lt;br /&gt;(Support for transitive dependency management without the need for remote repositories or pom.xml and ivy.xml files.)&lt;/LI&gt;
&lt;LI&gt;그루비 문법 사용 (Groovy build scripts.)&lt;/LI&gt;
&lt;LI&gt;빌드를 설명하는 풍부한 도메인 모델 (A rich domain model for describing your build.)&lt;/LI&gt;&lt;/UL&gt;&lt;/DIV&gt;
&lt;H2&gt;&lt;A class=tx-link href=&quot;https://gradle.org/maven-vs-gradle/#performance&quot; target=_blank&gt;Maven VS Gradle&lt;/A&gt;&lt;/H2&gt;
&lt;P&gt;Maven에는&amp;nbsp;gradle과 비교 문서가 없지만, gradle에는&amp;nbsp;비교문서가 존재. (비교에 자신있는 모습 ..ㅋ)&lt;/P&gt;
&lt;P&gt;Gradle이 시기적으로 늦게 나온만큼&amp;nbsp;사용성, 성능 등&amp;nbsp;비교적 뛰어난 스펙을 가지고있다.&lt;/P&gt;
&lt;P&gt;&lt;A class=tx-link href=&quot;http://kwonnam.pe.kr/wiki/gradle/from_maven&quot; target=_blank&gt;Gradle이 Maven보다 좋은점&lt;/A&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;Build라는 동적인 요소를 XML로 정의하기에는 어려운 부분이 많다.&lt;/LI&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&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;/UL&gt;
&lt;LI&gt;Gradle은 Groovy를 사용하기 때문에, 동적인 빌드는 Groovy 스크립트로 플러그인을 호출하거나 직접 코드를 짜면 된다.&lt;/LI&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;Configuration Injection 방식을 사용해서 공통 모듈을 상속해서 사용하는 단점을 커버했다.&lt;/LI&gt;
&lt;LI&gt;설정 주입 시 프로젝트의 조건을 체크할 수 있어서 프로젝트별로 주입되는 설정을 다르게 할 수 있다.&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A class=tx-link href=&quot;https://gradle.org/gradle-vs-maven-performance/&quot; target=_blank&gt;Gradle vs Maven: Performance Comparison&lt;/A&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;600명의 엔지니어가 1년동안 1분걸리는 빌드를&amp;nbsp;매주&amp;nbsp;42번 빌드를 진행할 때&amp;nbsp;들어가는 비용은&lt;br /&gt;&lt;SPAN style='FONT-SIZE: 13px; FONT-FAMILY: &quot;Source Code Pro&quot;, &quot;Courier New&quot;, monospace; WHITE-SPACE: normal; WORD-SPACING: 0px; TEXT-TRANSFORM: none; FLOAT: none; FONT-WEIGHT: 500; COLOR: rgb(191,97,106); FONT-STYLE: normal; ORPHANS: 2; WIDOWS: 2; DISPLAY: inline !important; LETTER-SPACING: normal; BACKGROUND-COLOR: rgb(249,249,249); TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial'&gt;600 engineers * $1.42/minutes * 42 builds/week * 44 work weeks/year = $1,600,000/year&lt;/SPAN&gt;&lt;br /&gt;이때 빌드 속도가 90% 빨라진다면?&lt;/LI&gt;
&lt;LI&gt;Gradle은&amp;nbsp;메이븐 보다 최대 100배 빠르다.&lt;/LI&gt;
&lt;LI style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 665px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/267F8745595B0BB601&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F267F8745595B0BB601&quot; width=&quot;665&quot; height=&quot;324&quot; filename=&quot;lib.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/LI&gt;
&lt;LI style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 658px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/262E4845595B0BB60A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F262E4845595B0BB60A&quot; width=&quot;658&quot; height=&quot;325&quot; filename=&quot;sm.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/LI&gt;
&lt;LI style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 666px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/25548345595B0BB718&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F25548345595B0BB718&quot; width=&quot;666&quot; height=&quot;332&quot; filename=&quot;mm.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/LI&gt;
&lt;LI style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 664px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/26162D45595B0BB710&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F26162D45595B0BB710&quot; width=&quot;664&quot; height=&quot;331&quot; filename=&quot;lm.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/LI&gt;
&lt;LI&gt;어떻게?&lt;/LI&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;the &lt;A class=tx-link href=&quot;https://docs.gradle.org/current/userguide/gradle_daemon.html&quot; target=_blank&gt;Gradle Daemon&lt;/A&gt; is a long-lived process that keeps build information “hot” in memory&lt;/LI&gt;
&lt;LI&gt;&lt;A class=tx-link href=&quot;https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:up_to_date_checks&quot; target=_blank&gt;incremental task inputs and output&lt;/A&gt;s for various types of tasks makes it unnecessary to run clean ever again&lt;/LI&gt;
&lt;LI&gt;&lt;A class=tx-link href=&quot;https://docs.gradle.org/current/userguide/java_plugin.html#sec:incremental_compile&quot; target=_blank&gt;incremental compilation&lt;/A&gt; analyzes the dependencies between your sources and classes and recompiles only those which are affected by changes&lt;/LI&gt;
&lt;LI&gt;the &lt;A class=tx-link href=&quot;https://docs.gradle.org/current/userguide/build_cache.html&quot; target=_blank&gt;build cache&lt;/A&gt; fetches results from a cache when switching branches or running a clean build and the same output has already been produced somewhere else in the organization.&lt;/LI&gt;
&lt;LI&gt;Gradle’s &lt;A class=tx-link href=&quot;https://blog.gradle.org/incremental-compiler-avoidance&quot; target=_blank&gt;smart classpath analyzer&lt;/A&gt; avoids unnecessary compilation when the binary interface of a library hasn’t changed&lt;/LI&gt;
&lt;LI&gt;better modelling of dependencies using the &lt;A class=tx-link href=&quot;https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation&quot; target=_blank&gt;Java Library plugin&lt;/A&gt; reduces the size of the compile classpath which has a large, positive impact on performance&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;H2&gt;예제&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;스프링부트를 이용하여&amp;nbsp;같은 기능과&amp;nbsp;라이브러리 의존성을 가지는&amp;nbsp;Maven, Gradle 프로젝트를 생성해 보았다. (Java 1.8, Spring Boot 1.5.4)&lt;/P&gt;
&lt;OL style=&quot;LIST-STYLE-TYPE: decimal&quot;&gt;
&lt;LI&gt;스크립트 길이와 가독성 면에서 Gradle(groovy)이&amp;nbsp; 앞선다.&lt;/LI&gt;
&lt;LI&gt;빌드와 테스트 실행 결과 Gradle이 더 빠르다. (Gradle이 캐시를 사용하기 때문에 테스트 반복 시 차이가 더 커진다.)&lt;/LI&gt;
&lt;LI&gt;의존성이 늘어날 수록 성능과 스크립트 품질의 차이가 심해질 것이다.&lt;/LI&gt;&lt;/OL&gt;&lt;/DIV&gt;&lt;PRE style=&quot;FONT-SIZE: 9.8pt; FONT-FAMILY: 'Lucida Sans Typewriter'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;SPAN style=&quot;COLOR: #ffffff; BACKGROUND-COLOR: #ff0000&quot;&gt;Maven&lt;/SPAN&gt;&lt;br /&gt;&amp;lt;?&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;xml version&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;=&quot;1.0&quot; &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;encoding&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;=&quot;UTF-8&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;?&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;project &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;xmlns&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;=&quot;http://maven.apache.org/POM/4.0.0&quot; &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;xmlns:&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #9876aa&quot;&gt;xsi&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;   &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #9876aa&quot;&gt;xsi&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;:schemaLocation&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;modelVersion&amp;gt;&lt;/SPAN&gt;4.0.0&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;groupId&amp;gt;&lt;/SPAN&gt;com.example&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;artifactId&amp;gt;&lt;/SPAN&gt;demo-maven&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;version&amp;gt;&lt;/SPAN&gt;0.0.1-SNAPSHOT&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;packaging&amp;gt;&lt;/SPAN&gt;jar&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/packaging&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;name&amp;gt;&lt;/SPAN&gt;demo-maven&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/name&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;description&amp;gt;&lt;/SPAN&gt;Demo project for Spring Boot&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/description&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;parent&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;groupId&amp;gt;&lt;/SPAN&gt;org.springframework.boot&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;artifactId&amp;gt;&lt;/SPAN&gt;spring-boot-starter-parent&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;version&amp;gt;&lt;/SPAN&gt;1.5.4.RELEASE&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;relativePath/&amp;gt; &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #808080&quot;&gt;&amp;lt;!-- lookup parent from repository --&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #808080&quot;&gt;   &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/parent&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;properties&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;project.build.sourceEncoding&amp;gt;&lt;/SPAN&gt;UTF-8&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/project.build.sourceEncoding&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;project.reporting.outputEncoding&amp;gt;&lt;/SPAN&gt;UTF-8&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/project.reporting.outputEncoding&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;java.version&amp;gt;&lt;/SPAN&gt;1.8&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/java.version&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;/properties&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;dependencies&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;         &amp;lt;groupId&amp;gt;&lt;/SPAN&gt;org.springframework.boot&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;         &amp;lt;artifactId&amp;gt;&lt;/SPAN&gt;spring-boot-starter&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;         &amp;lt;groupId&amp;gt;&lt;/SPAN&gt;org.springframework.boot&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;         &amp;lt;artifactId&amp;gt;&lt;/SPAN&gt;spring-boot-starter-test&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;         &amp;lt;scope&amp;gt;&lt;/SPAN&gt;test&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/scope&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;/dependencies&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;build&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;plugins&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;         &amp;lt;plugin&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;            &amp;lt;groupId&amp;gt;&lt;/SPAN&gt;org.springframework.boot&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;            &amp;lt;artifactId&amp;gt;&lt;/SPAN&gt;spring-boot-maven-plugin&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;         &amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;      &amp;lt;/plugins&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;   &amp;lt;/build&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/project&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;PRE style=&quot;FONT-SIZE: 9.8pt; FONT-FAMILY: 'Lucida Sans Typewriter'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;&lt;SPAN style=&quot;COLOR: #ffffff; BACKGROUND-COLOR: #ff0000&quot;&gt;Gradle&lt;/SPAN&gt;&lt;br /&gt;buildscript {&lt;br /&gt;    ext {&lt;br /&gt;        springBootVersion = &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'1.5.4.RELEASE'&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;    &lt;/SPAN&gt;}&lt;br /&gt;    repositories {&lt;br /&gt;        mavenCentral()&lt;br /&gt;    }&lt;br /&gt;    dependencies {&lt;br /&gt;        classpath(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;&quot;org.springframework.boot:spring-boot-gradle-plugin:&lt;/SPAN&gt;${springBootVersion}&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;&quot;&lt;/SPAN&gt;)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;apply &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;plugin&lt;/SPAN&gt;: &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'java'&lt;br /&gt;&lt;/SPAN&gt;apply &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;plugin&lt;/SPAN&gt;: &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'idea'&lt;br /&gt;&lt;/SPAN&gt;apply &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;plugin&lt;/SPAN&gt;: &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'org.springframework.boot'&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #9876aa&quot;&gt;version &lt;/SPAN&gt;= &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'0.0.1-SNAPSHOT'&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #9876aa&quot;&gt;sourceCompatibility &lt;/SPAN&gt;= &lt;SPAN style=&quot;COLOR: #6897bb&quot;&gt;1.8&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6897bb&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;repositories {&lt;br /&gt;    mavenCentral()&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;dependencies {&lt;br /&gt;    compile(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'org.springframework.boot:spring-boot-starter'&lt;/SPAN&gt;)&lt;br /&gt;    testCompile(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'org.springframework.boot:spring-boot-starter-test'&lt;/SPAN&gt;)&lt;br /&gt;}&lt;/PRE&gt;
&lt;H2&gt;결론&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;지금 시점에서 Gradle을 사용하지 않을 이유는 '익숙함' 뿐인 것 같다.&lt;/P&gt;
&lt;P&gt;Gradle이 출시되었을 때에는 Maven이 지원하는&amp;nbsp;Scope를 지원하지 않았고 성능면에서도 앞설것이 없었다.&lt;/P&gt;
&lt;P&gt;Ant의 유연한 구조적 장점과 Maven의 편리한 의존성 관리 기능을 합쳐놓은 것만으로도 많은 인기를 얻었던 Gradle은 버전이 올라가며&amp;nbsp;성능이라는 장점까지 더해지면서 대세가 되었다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;물론 그동안 사용해왔던 Maven과 이제는 익숙해진 XML을 버리고 Gradle과 Groovy문법을 배우는 것은 적지않은 비용이 든다.&lt;/P&gt;
&lt;P&gt;특히 협업을 하는 경우, 프로젝트&amp;nbsp;구성과&amp;nbsp;빌드만을 위해&amp;nbsp;모든 팀원이 Groovy 문법을 익여야 한다는 사실은 Gradle를 사용하는데 큰 걸림돌이 된다.&lt;/P&gt;
&lt;P&gt;실제로 여전히 Maven의 사용률은&amp;nbsp;Gradle을 앞서고 있으며 &lt;A class=tx-link href=&quot;https://trends.google.com/trends/explore?q=gradle,maven&quot; target=_blank&gt;구글 트랜드 지수&lt;/A&gt;도 Maven이 Gradle을 앞선다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;협업과 러닝커브를 고려하여 여전이 Maven를 사용하는 팀이 많고 부족함 없이 잘 사용하고 있지만,&lt;/P&gt;
&lt;P&gt;앞서 요약했듯 프로젝트의 빌드타임이 비용문제로 이어질 경우 Gradle을 사용해야 할 것 같다. &lt;/P&gt;
&lt;P&gt;리드미컬?하게 테스트를 진행하고 민첩한? 지속적 배포를 생각하고 있다면 새로움 배움이 필요하더라도&amp;nbsp;Gradle을 사용해보자. 아자.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;/DIV&gt;
&lt;H2&gt;출처&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;&lt;A href=&quot;https://gradle.org/&quot;&gt;https://gradle.org/&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href=&quot;https://maven.apache.org/&quot;&gt;https://maven.apache.org/&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href=&quot;http://egloos.zum.com/kwon37xi/v/4747016&quot;&gt;http://egloos.zum.com/kwon37xi/v/4747016&lt;/A&gt;&lt;/P&gt;&lt;/DIV&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;/STRONG&gt;</description>
      <category>SPRING</category>
      <category>gradle</category>
      <category>Maven</category>
      <category>비교</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/13</guid>
      <comments>https://bkim.tistory.com/13#entry13comment</comments>
      <pubDate>Tue, 4 Jul 2017 10:27:58 +0900</pubDate>
    </item>
    <item>
      <title>Nginx 설치하기 (컴파일 설치, CentOS 6.8, nginx-1.12.0)</title>
      <link>https://bkim.tistory.com/12</link>
      <description>&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;Nginx는 컴파일된 바이너리를 제공하지 않는다.&lt;/P&gt;
&lt;P&gt;apt-get이나 yum을 통해 설치하면 설정 관리나, 이중화같은 작업이 어렵기 때문에&amp;nbsp;컴파일 설치를 선호하는 편이다.&lt;/P&gt;
&lt;P&gt;2017년 6월 23일 기준 최신 Stable version인 nginx-1.12.0 버전 설치 스크립트를 아래 작성했다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;설치 기준 위치는 &lt;STRONG&gt;/home/username/apps/&lt;/STRONG&gt; 로 한다.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3&gt;1. NGINX 다운로드&lt;/H3&gt;
&lt;DIV class=&quot;code panel pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: auto; BORDER-TOP: rgb(204,204,204) 1px solid; FONT-FAMILY: Arial, sans-serif; BORDER-RIGHT: rgb(204,204,204) 1px solid; WHITE-SPACE: normal; WORD-SPACING: 0px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; FONT-STYLE: normal; PADDING-TOP: 0px; PADDING-LEFT: 0px; BORDER-LEFT: rgb(204,204,204) 1px solid; ORPHANS: 2; WIDOWS: 2; MARGIN: 10px 0px; LETTER-SPACING: normal; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; border-radius: 3px&quot;&gt;
&lt;DIV class=&quot;codeContent panelContent pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: hidden; BACKGROUND: rgb(255,255,255); COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; TEXT-ALIGN: left; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; LINE-HEIGHT: 20px; PADDING-RIGHT: 0px; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px&quot;&gt;
&lt;DIV style=&quot;PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px&quot;&gt;
&lt;DIV id=highlighter_529288 class=&quot;syntaxhighlighter nogutter  java&quot; style=&quot;FONT-SIZE: 1em !important; OVERFLOW: auto !important; WIDTH: 1059px; POSITION: relative !important; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255)&quot;&gt;
&lt;TABLE style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1059px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px' cellSpacing=0 cellPadding=0 border=0&gt;
&lt;TBODY style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TR style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TD class=code style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1044px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 15px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV title=&quot;Hint: double-click to select code&quot; class=container style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; WHITE-SPACE: pre-wrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: relative !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 15px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 15px 0px 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV class=&quot;line number1 index0 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;cd /home/username/apps/&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number2 index1 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;wget https:&lt;/CODE&gt;&lt;CODE class=&quot;java comments&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,130,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;//nginx.org/download/nginx-1.12.0.tar.gz&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number3 index2 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;tar -xvf nginx-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.12&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;0&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.tar.gz&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number4 index3 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;rm nginx-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.12&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;0&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.tar.gz&lt;/CODE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;H3&gt;2. PCRE 다운로드&lt;/H3&gt;
&lt;DIV class=&quot;code panel pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: auto; BORDER-TOP: rgb(204,204,204) 1px solid; FONT-FAMILY: Arial, sans-serif; BORDER-RIGHT: rgb(204,204,204) 1px solid; WHITE-SPACE: normal; WORD-SPACING: 0px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; FONT-STYLE: normal; PADDING-TOP: 0px; PADDING-LEFT: 0px; BORDER-LEFT: rgb(204,204,204) 1px solid; ORPHANS: 2; WIDOWS: 2; MARGIN: 10px 0px; LETTER-SPACING: normal; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; border-radius: 3px&quot;&gt;
&lt;DIV class=&quot;codeContent panelContent pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: hidden; BACKGROUND: rgb(255,255,255); COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; TEXT-ALIGN: left; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; LINE-HEIGHT: 20px; PADDING-RIGHT: 0px; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px&quot;&gt;
&lt;DIV style=&quot;PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px&quot;&gt;
&lt;DIV id=highlighter_321057 class=&quot;syntaxhighlighter nogutter  java&quot; style=&quot;FONT-SIZE: 1em !important; OVERFLOW: auto !important; WIDTH: 1059px; POSITION: relative !important; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255)&quot;&gt;
&lt;TABLE style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1059px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px' cellSpacing=0 cellPadding=0 border=0&gt;
&lt;TBODY style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TR style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TD class=code style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1044px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 15px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV title=&quot;Hint: double-click to select code&quot; class=container style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; WHITE-SPACE: pre-wrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: relative !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 15px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 15px 0px 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV class=&quot;line number1 index0 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;cd /home/username/apps/nginx-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.12&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;0&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number2 index1 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;wget http:&lt;/CODE&gt;&lt;CODE class=&quot;java comments&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,130,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;//downloads.sourceforge.net/project/pcre/pcre/8.37/pcre-8.37.tar.gz&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number3 index2 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;tar -zxf pcre-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;8.37&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.tar.gz&lt;/CODE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;H3&gt;3. zlib 다운로드&lt;/H3&gt;
&lt;DIV class=&quot;code panel pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: auto; BORDER-TOP: rgb(204,204,204) 1px solid; FONT-FAMILY: Arial, sans-serif; BORDER-RIGHT: rgb(204,204,204) 1px solid; WHITE-SPACE: normal; WORD-SPACING: 0px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; FONT-STYLE: normal; PADDING-TOP: 0px; PADDING-LEFT: 0px; BORDER-LEFT: rgb(204,204,204) 1px solid; ORPHANS: 2; WIDOWS: 2; MARGIN: 10px 0px; LETTER-SPACING: normal; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; border-radius: 3px&quot;&gt;
&lt;DIV class=&quot;codeContent panelContent pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: hidden; BACKGROUND: rgb(255,255,255); COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; TEXT-ALIGN: left; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; LINE-HEIGHT: 20px; PADDING-RIGHT: 0px; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px&quot;&gt;
&lt;DIV style=&quot;PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px&quot;&gt;
&lt;DIV id=highlighter_923737 class=&quot;syntaxhighlighter nogutter  java&quot; style=&quot;FONT-SIZE: 1em !important; OVERFLOW: auto !important; WIDTH: 1059px; POSITION: relative !important; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255)&quot;&gt;
&lt;TABLE style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1059px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px' cellSpacing=0 cellPadding=0 border=0&gt;
&lt;TBODY style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TR style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TD class=code style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1044px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 15px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV title=&quot;Hint: double-click to select code&quot; class=container style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; WHITE-SPACE: pre-wrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: relative !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 15px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 15px 0px 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV class=&quot;line number1 index0 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;cd /home/username/apps/nginx-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.12&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;0&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number2 index1 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;wget http:&lt;/CODE&gt;&lt;CODE class=&quot;java comments&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,130,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;//zlib.net/zlib-1.2.11.tar.gz&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number3 index2 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;tar -zxf zlib-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.2&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;11&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.tar.gz&lt;/CODE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;H3&gt;4. OpenSSL 다운로드&lt;/H3&gt;
&lt;DIV class=&quot;code panel pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: auto; BORDER-TOP: rgb(204,204,204) 1px solid; FONT-FAMILY: Arial, sans-serif; BORDER-RIGHT: rgb(204,204,204) 1px solid; WHITE-SPACE: normal; WORD-SPACING: 0px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; FONT-STYLE: normal; PADDING-TOP: 0px; PADDING-LEFT: 0px; BORDER-LEFT: rgb(204,204,204) 1px solid; ORPHANS: 2; WIDOWS: 2; MARGIN: 10px 0px; LETTER-SPACING: normal; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; border-radius: 3px&quot;&gt;
&lt;DIV class=&quot;codeContent panelContent pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: hidden; BACKGROUND: rgb(255,255,255); COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; TEXT-ALIGN: left; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; LINE-HEIGHT: 20px; PADDING-RIGHT: 0px; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px&quot;&gt;
&lt;DIV style=&quot;PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px&quot;&gt;
&lt;DIV id=highlighter_658227 class=&quot;syntaxhighlighter nogutter  java&quot; style=&quot;FONT-SIZE: 1em !important; OVERFLOW: auto !important; WIDTH: 1059px; POSITION: relative !important; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255)&quot;&gt;
&lt;TABLE style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1059px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px' cellSpacing=0 cellPadding=0 border=0&gt;
&lt;TBODY style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TR style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TD class=code style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1044px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 15px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV title=&quot;Hint: double-click to select code&quot; class=container style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; WHITE-SPACE: pre-wrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: relative !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 15px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 15px 0px 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV class=&quot;line number1 index0 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;cd /home/username/apps/nginx-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.12&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;0&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number2 index1 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;wget http:&lt;/CODE&gt;&lt;CODE class=&quot;java comments&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,130,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;//www.openssl.org/source/openssl-1.0.2f.tar.gz&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number3 index2 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;tar -zxf openssl-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.0&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.2f.tar.gz&lt;/CODE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;H3&gt;5. NGINX 설치&lt;/H3&gt;
&lt;DIV class=&quot;code panel pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: auto; BORDER-TOP: rgb(204,204,204) 1px solid; FONT-FAMILY: Arial, sans-serif; BORDER-RIGHT: rgb(204,204,204) 1px solid; WHITE-SPACE: normal; WORD-SPACING: 0px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; FONT-STYLE: normal; PADDING-TOP: 0px; PADDING-LEFT: 0px; BORDER-LEFT: rgb(204,204,204) 1px solid; ORPHANS: 2; WIDOWS: 2; MARGIN: 10px 0px; LETTER-SPACING: normal; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; border-radius: 3px&quot;&gt;
&lt;DIV class=&quot;codeContent panelContent pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: hidden; BACKGROUND: rgb(255,255,255); COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; TEXT-ALIGN: left; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; LINE-HEIGHT: 20px; PADDING-RIGHT: 0px; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px&quot;&gt;
&lt;DIV style=&quot;PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px&quot;&gt;
&lt;DIV id=highlighter_428452 class=&quot;syntaxhighlighter nogutter  java&quot; style=&quot;FONT-SIZE: 1em !important; OVERFLOW: auto !important; WIDTH: 1059px; POSITION: relative !important; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255)&quot;&gt;
&lt;TABLE style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1423px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px' cellSpacing=0 cellPadding=0 border=0&gt;
&lt;TBODY style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TR style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TD class=code style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1408px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 15px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV title=&quot;Hint: double-click to select code&quot; class=container style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; WHITE-SPACE: pre-wrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: relative !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 15px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 15px 0px 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV class=&quot;line number1 index0 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;cd /home/username/apps/nginx-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.12&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;0&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number2 index1 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;./configure --prefix=/home/username/apps/nginx --with-zlib=./zlib-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.2&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;11&lt;/CODE&gt;&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;--with-pcre=./pcre-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;8.37&lt;/CODE&gt;&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;--with-openssl=./openssl-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.0&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.2f --with-http_ssl_module --with-http_stub_status_module&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number3 index2 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;make install&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number4 index3 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;cd /home/username/apps/&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number5 index4 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;rm -rf nginx-&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;1.12&lt;/CODE&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;.&lt;/CODE&gt;&lt;CODE class=&quot;java value&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,153,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;0&lt;/CODE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;H3&gt;6. 실행권한 설정&lt;/H3&gt;
&lt;DIV class=&quot;code panel pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: auto; BORDER-TOP: rgb(204,204,204) 1px solid; FONT-FAMILY: Arial, sans-serif; BORDER-RIGHT: rgb(204,204,204) 1px solid; WHITE-SPACE: normal; WORD-SPACING: 0px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; FONT-STYLE: normal; PADDING-TOP: 0px; PADDING-LEFT: 0px; BORDER-LEFT: rgb(204,204,204) 1px solid; ORPHANS: 2; WIDOWS: 2; MARGIN: 10px 0px; LETTER-SPACING: normal; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; border-radius: 3px&quot;&gt;
&lt;DIV class=&quot;codeContent panelContent pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: hidden; BACKGROUND: rgb(255,255,255); COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; TEXT-ALIGN: left; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; LINE-HEIGHT: 20px; PADDING-RIGHT: 0px; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px&quot;&gt;
&lt;DIV style=&quot;PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px&quot;&gt;
&lt;DIV id=highlighter_233518 class=&quot;syntaxhighlighter nogutter  java&quot; style=&quot;FONT-SIZE: 1em !important; OVERFLOW: auto !important; WIDTH: 1059px; POSITION: relative !important; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255)&quot;&gt;
&lt;TABLE style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1059px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px' cellSpacing=0 cellPadding=0 border=0&gt;
&lt;TBODY style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TR style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TD class=code style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1044px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 15px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV title=&quot;Hint: double-click to select code&quot; class=container style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; WHITE-SPACE: pre-wrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: relative !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 15px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 15px 0px 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV class=&quot;line number1 index0 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;cd /home/username/apps/nginx/sbin&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number2 index1 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;sudo chown root nginx&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number3 index2 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;sudo chmod +s nginx&lt;/CODE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;H3&gt;7. 실행 및 테스트&lt;/H3&gt;
&lt;DIV id=main-content class=wiki-content style=&quot;FONT-SIZE: 14px; FONT-FAMILY: Arial, sans-serif; WHITE-SPACE: normal; WORD-SPACING: 0px; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; FONT-STYLE: normal; PADDING-TOP: 0px; PADDING-LEFT: 0px; ORPHANS: 2; WIDOWS: 2; MARGIN: 0px; LETTER-SPACING: normal; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial&quot;&gt;
&lt;DIV class=&quot;code panel pdl&quot; style=&quot;OVERFLOW: auto; BORDER-TOP: rgb(204,204,204) 1px solid; BORDER-RIGHT: rgb(204,204,204) 1px solid; BORDER-BOTTOM: rgb(204,204,204) 1px solid; COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; BORDER-LEFT: rgb(204,204,204) 1px solid; MARGIN: 10px 0px; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255); border-radius: 3px&quot;&gt;
&lt;DIV class=&quot;codeContent panelContent pdl&quot; style=&quot;FONT-SIZE: 14px; OVERFLOW: hidden; BACKGROUND: rgb(255,255,255); COLOR: rgb(51,51,51); PADDING-BOTTOM: 0px; TEXT-ALIGN: left; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; LINE-HEIGHT: 20px; PADDING-RIGHT: 0px; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px&quot;&gt;
&lt;DIV style=&quot;PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px&quot;&gt;
&lt;DIV id=highlighter_198868 class=&quot;syntaxhighlighter nogutter  java&quot; style=&quot;FONT-SIZE: 1em !important; OVERFLOW: auto !important; WIDTH: 1059px; POSITION: relative !important; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255)&quot;&gt;
&lt;TABLE style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1059px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px' cellSpacing=0 cellPadding=0 border=0&gt;
&lt;TBODY style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TR style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;TD class=code style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: 1044px; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 15px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV title=&quot;Hint: double-click to select code&quot; class=container style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; WHITE-SPACE: pre-wrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: relative !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 15px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 15px 0px 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;
&lt;DIV class=&quot;line number1 index0 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;cd /home/username/apps/nginx/sbin&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number2 index1 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;./nginx&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;CODE class=&quot;java comments&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,130,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;//시작&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number3 index2 alt2&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java comments&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,130,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;//포트 80 이 사용중이면, &lt;FONT color=#000000&gt;/home/username/apps/&lt;/FONT&gt;nginx/conf/nginx.conf 에서 liten 80 을 변경해주면 된다. 
&lt;P&gt;//자신의 서버 ip:prot 로 접근해보면 nginx index페이지 뜬것을 확인 할 수 있다.&amp;nbsp;&lt;/P&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class=&quot;line number4 index3 alt1&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: rgb(255,255,255); WHITE-SPACE: nowrap !important; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 1em !important; BOTTOM: auto !important; border-radius: 0px'&gt;&lt;CODE class=&quot;java plain&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,0,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;./nginx -s stop&amp;nbsp;&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;CODE class=&quot;java comments&quot; style='BOX-SIZING: content-box !important; FONT-SIZE: 14px !important; OVERFLOW: visible !important; BORDER-TOP: 0px; HEIGHT: auto !important; FONT-FAMILY: Consolas, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important; BORDER-RIGHT: 0px; WIDTH: auto !important; VERTICAL-ALIGN: baseline !important; BACKGROUND: none transparent scroll repeat 0% 0%; RIGHT: auto !important; BORDER-BOTTOM: 0px; POSITION: static !important; FLOAT: none !important; FONT-WEIGHT: normal !important; COLOR: rgb(0,130,0) !important; OUTLINE-WIDTH: 0px !important; PADDING-BOTTOM: 0px !important; FONT-STYLE: normal !important; TEXT-ALIGN: left !important; PADDING-TOP: 0px !important; OUTLINE-STYLE: none !important; PADDING-LEFT: 0px !important; LEFT: auto !important; MIN-HEIGHT: auto !important; BORDER-LEFT: 0px; MARGIN: 0px; OUTLINE-COLOR: invert !important; LINE-HEIGHT: 20px !important; TOP: auto !important; PADDING-RIGHT: 0px !important; BOTTOM: auto !important; border-radius: 0px'&gt;//종료&lt;/CODE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;DIV id=likes-and-labels-container style=&quot;FONT-SIZE: 14px; OVERFLOW: hidden; FONT-FAMILY: Arial, sans-serif; WHITE-SPACE: normal; WORD-SPACING: 0px; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(51,51,51); PADDING-BOTTOM: 10px; FONT-STYLE: normal; PADDING-TOP: 10px; PADDING-LEFT: 0px; CLEAR: both; ORPHANS: 2; WIDOWS: 2; MARGIN: 10px 0px; LETTER-SPACING: normal; PADDING-RIGHT: 0px; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial&quot;&gt;
&lt;DIV id=likes-section style=&quot;FONT-SIZE: 13px; WIDTH: 509px; FLOAT: left; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; PADDING-RIGHT: 0px&quot;&gt;&lt;BR class=Apple-interchange-newline&gt;&lt;/DIV&gt;
&lt;P style=&quot;TEXT-ALIGN: left&quot;&gt;&amp;nbsp;&lt;/P&gt;&lt;/DIV&gt;</description>
      <category>WEB</category>
      <category>CentOS</category>
      <category>compile</category>
      <category>Linux</category>
      <category>nginx</category>
      <category>nginx binary</category>
      <category>nginx 설치</category>
      <category>설치</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/12</guid>
      <comments>https://bkim.tistory.com/12#entry12comment</comments>
      <pubDate>Fri, 23 Jun 2017 12:14:03 +0900</pubDate>
    </item>
    <item>
      <title>Html5 Video Player 알아보기, 개발하기</title>
      <link>https://bkim.tistory.com/11</link>
      <description>&lt;H2&gt;HTML5 Video Tag&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #dbe8fb 1px solid; BORDER-RIGHT: #dbe8fb 1px solid; BORDER-BOTTOM: #dbe8fb 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #dbe8fb 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #dbe8fb&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;B&gt;HTML5&lt;/B&gt;는&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A style=&quot;TEXT-DECORATION: none; BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: rgb(11,0,128)&quot; href=&quot;https://ko.wikipedia.org/wiki/HTML&quot;&gt;HTML&lt;/A&gt;의 완전한 5번째 버전으로 월드 와이드 웹 (World Wide Web)의 핵심&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A style=&quot;TEXT-DECORATION: none; BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: rgb(11,0,128)&quot; href=&quot;https://ko.wikipedia.org/wiki/%EB%A7%88%ED%81%AC%EC%97%85_%EC%96%B8%EC%96%B4&quot;&gt;마크업 언어&lt;/A&gt;이다. 2004년 7월 Web Hypertext Application Technology Working Group(WHATWG)에서 웹 애플리케이션 1.0이라는 이름으로 세부 명세 작업을 시작하였다. 
&lt;P&gt;HTML5는&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A class=new style=&quot;TEXT-DECORATION: none; BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: rgb(165,88,88)&quot; href=&quot;https://ko.wikipedia.org/w/index.php?title=HTML_4.01&amp;amp;action=edit&amp;amp;redlink=1&quot;&gt;HTML 4.01&lt;/A&gt;,&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A style=&quot;TEXT-DECORATION: none; BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: rgb(11,0,128)&quot; href=&quot;https://ko.wikipedia.org/wiki/XHTML&quot;&gt;XHTML&lt;/A&gt;&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;1.0, DOM 레벨 2 HTML에 대한 차기 표준 제안이다. 비디오, 오디오 등 다양한 부가기능과 최신 멀티미디어 콘텐츠를&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A style=&quot;TEXT-DECORATION: none; BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: rgb(11,0,128)&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%95%A1%ED%8B%B0%EB%B8%8CX&quot;&gt;액티브X&lt;/A&gt;&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;없이 브라우저에서 쉽게 볼 수 있게 하는 것을 목적으로 한다.&lt;br /&gt;&amp;nbsp;&lt;A style=&quot;TEXT-DECORATION: none; BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: rgb(11,0,128)&quot; href=&quot;https://ko.wikipedia.org/wiki/W3C&quot;&gt;W3C&lt;/A&gt;는 2014년 10월 28일 HTML5 표준안을 확정했다고 발표했다. - &lt;A class=tx-link href=&quot;https://ko.wikipedia.org/wiki/HTML5&quot; target=_blank&gt;https://ko.wikipedia.org/wiki/HTML5&lt;/A&gt;&lt;br /&gt;&lt;/P&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;HTML4에서 5로 넘어오면서 audio, video, canvas라는 멀티미디어 관련 태그가 추가되었다.&lt;/P&gt;
&lt;P&gt;W3C는 2004년 새로운 표준을 제안하였고, 단계적으로 HTML5를 지원하는 범위를 넓혀가던 2007년까지 HTML5에 대한 시선이 곱지만은 않았다.&lt;/P&gt;
&lt;P&gt;이제는 레거시 시스템이 된 Silver Light와 Flash, Active X가 라이벌을 물리치고 평정한 시대였고, 브라우저가 HTML5를 랜더링하는 성능도 눈에 뛰게&amp;nbsp;부족했기 때문이었다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;하지만 HTML5가 있으면&amp;nbsp;모든 클라이언트&amp;nbsp;서비스(읽고, 쓰고, 보고, 듣는)를 지원할 수 있다는 희망이 생겨났고, 이를 증명하듯 수많은 웹앱이 태어났다. 스마트폰과 하드웨어의 발전이 계속되고 복잡한 웹생태계를 표준화하고자 하는 사람들의 열망이 모여 현재 Flash와 Silver Light, Actice X는 레거시를 넘어 웹생태계를 해치는 악의 축으로 밀려 나기 까지 했는데, 이러한 HTML5 내용 중 Video에 대해서 살펴보고자 한다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Video element 는 Medeia element를 구현하고 있으며, 속성으로 src, poster, preload, autoplay, mediagroup, loop, muted, controls, width, height 속성을 가진다. DOM생성시 해당 옵션을 지정할 수 있으며 이름을 통해서 알 수 있듯이 플레이어가 지원해야할 기본적인 옵션들이다.&lt;/P&gt;
&lt;P&gt;Video element의 DOM interface로는 width, height, videoWidth, videoHeight, poster가 있고, Media elemet에 current와 duration 같은 좀 더 상세한 interface가 있다.&amp;nbsp; 상세내용은 아래에 첨부하였다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A class=tx-link href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#video&quot; target=_blank&gt;&lt;SPAN style=&quot;COLOR: #ff0000&quot;&gt;W3C&amp;nbsp; Video 정의&lt;/SPAN&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt; COLOR: #003399&quot;&gt;Video Element&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;br /&gt;&lt;/P&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;Content attributes&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 2em&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;src&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;poster&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;preload&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;autoplay&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;mediagroup&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;loop&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;muted&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;controls&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;width&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;height&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;br /&gt;&lt;/P&gt;&lt;/SPAN&gt;
&lt;DT style=&quot;FONT-SIZE: medium; MARGIN-BOTTOM: 0px; FONT-FAMILY: sans-serif; WHITE-SPACE: normal; WORD-SPACING: 0px; MARGIN-TOP: 0px; TEXT-TRANSFORM: none; FONT-WEIGHT: bold; COLOR: rgb(0,0,0); FONT-STYLE: normal; TEXT-ALIGN: left; CLEAR: left; ORPHANS: 2; WIDOWS: 2; LETTER-SPACING: normal; TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; break-after: avoid&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;DOM interface&lt;/SPAN&gt;&lt;/DT&gt;
&lt;DD style=&quot;FONT-SIZE: medium; MARGIN-BOTTOM: 0px; FONT-FAMILY: sans-serif; WHITE-SPACE: normal; WORD-SPACING: 0px; MARGIN-TOP: 0px; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(0,0,0); FONT-STYLE: normal; ORPHANS: 2; WIDOWS: 2; LETTER-SPACING: normal; TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial&quot;&gt;&lt;PRE class=idl style=&quot;BORDER-TOP: thin solid; FONT-FAMILY: monospace; BORDER-RIGHT: thin solid; BACKGROUND: rgb(238,238,238); WHITE-SPACE: pre-wrap; BORDER-BOTTOM: thin solid; COLOR: black; PADDING-BOTTOM: 0.5em; PADDING-TOP: 0.5em; PADDING-LEFT: 1em; MARGIN-LEFT: 2em; BORDER-LEFT: thin solid; PADDING-RIGHT: 1em; font-variant-ligatures: normal; font-variant-caps: normal&quot;&gt;interface &lt;DFN id=htmlvideoelement style=&quot;CURSOR: pointer; FONT-WEIGHT: bold; FONT-STYLE: normal&quot;&gt;HTMLVideoElement&lt;/DFN&gt; : &lt;A id=htmlmediaelement_0 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#htmlmediaelement&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;HTMLMediaElement&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; {
           attribute unsigned long &lt;A title='Read about this &quot;width&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/the-map-element.html#dom-dim-width&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;width&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute unsigned long &lt;A title='Read about this &quot;height&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/the-map-element.html#dom-dim-height&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;height&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute unsigned long &lt;A title='Read about this &quot;videoWidth&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-video-videowidth&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;videoWidth&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute unsigned long &lt;A title='Read about this &quot;videoHeight&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-video-videoheight&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;videoHeight&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute DOMString &lt;A title='Read about this &quot;poster&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-video-poster&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;poster&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
};&lt;/PRE&gt;&lt;/DD&gt;
&lt;P style=&quot;FONT-SIZE: medium; FONT-FAMILY: sans-serif; WHITE-SPACE: normal; WORD-SPACING: 0px; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(0,0,0); FONT-STYLE: normal; ORPHANS: 2; WIDOWS: 2; MARGIN: 1em 0px; LETTER-SPACING: normal; TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial&quot;&gt;&lt;DFN id=media-element title=&quot;media element&quot; style=&quot;CURSOR: pointer; FONT-WEIGHT: bold; FONT-STYLE: normal&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt; COLOR: #003399&quot;&gt;Media elements&lt;/SPAN&gt;&lt;/DFN&gt;&lt;SPAN class=Apple-converted-space style=&quot;FONT-SIZE: 11pt&quot;&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;(&lt;/SPAN&gt;&lt;CODE style=&quot;FONT-FAMILY: monospace; COLOR: orangered; font-variant-ligatures: normal; font-variant-caps: normal&quot;&gt;&lt;A id=audio_11 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#audio&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc face=&quot;Courier New&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;audio&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;&lt;/CODE&gt;&lt;SPAN class=Apple-converted-space style=&quot;FONT-SIZE: 11pt&quot;&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;and&lt;/SPAN&gt;&lt;SPAN class=Apple-converted-space style=&quot;FONT-SIZE: 11pt&quot;&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE style=&quot;FONT-FAMILY: monospace; COLOR: orangered; font-variant-ligatures: normal; font-variant-caps: normal&quot;&gt;&lt;A id=video_22 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#video&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc face=&quot;Courier New&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;video&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;&lt;/CODE&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;, in this specification) implement the following interface:&lt;/SPAN&gt;&lt;/P&gt;&lt;PRE class=idl style=&quot;BORDER-TOP: thin solid; FONT-FAMILY: monospace; BORDER-RIGHT: thin solid; BACKGROUND: rgb(238,238,238); WHITE-SPACE: pre-wrap; WORD-SPACING: 0px; BORDER-BOTTOM: thin solid; TEXT-TRANSFORM: none; FONT-WEIGHT: normal; COLOR: rgb(0,0,0); PADDING-BOTTOM: 0.5em; FONT-STYLE: normal; PADDING-TOP: 0.5em; PADDING-LEFT: 1em; MARGIN-LEFT: 2em; BORDER-LEFT: thin solid; ORPHANS: 2; WIDOWS: 2; LETTER-SPACING: normal; PADDING-RIGHT: 1em; TEXT-INDENT: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial&quot;&gt;interface &lt;DFN id=htmlmediaelement style=&quot;CURSOR: pointer; FONT-WEIGHT: bold; FONT-STYLE: normal&quot;&gt;HTMLMediaElement&lt;/DFN&gt; : &lt;A id=htmlelement_73 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/elements.html#htmlelement&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;HTMLElement&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; {

  // error state
  readonly attribute &lt;A id=mediaerror_0 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#mediaerror&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;MediaError&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; &lt;A title='Read about this &quot;error&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-error&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;error&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;

  // network state
           attribute DOMString &lt;A title='Read about this &quot;src&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-src&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;src&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute DOMString &lt;A title='Read about this &quot;currentSrc&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-currentsrc&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;currentSrc&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  const unsigned short &lt;A id=dom-media-network_empty_0 title=dom-media-NETWORK_EMPTY style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#dom-media-network_empty&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;NETWORK_EMPTY&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; = 0;
  const unsigned short &lt;A id=dom-media-network_idle_0 title=dom-media-NETWORK_IDLE style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#dom-media-network_idle&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;NETWORK_IDLE&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; = 1;
  const unsigned short &lt;A id=dom-media-network_loading_0 title=dom-media-NETWORK_LOADING style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#dom-media-network_loading&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;NETWORK_LOADING&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; = 2;
  const unsigned short &lt;A id=dom-media-network_no_source_0 title=dom-media-NETWORK_NO_SOURCE style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#dom-media-network_no_source&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;NETWORK_NO_SOURCE&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; = 3;
  readonly attribute unsigned short &lt;A title='Read about this &quot;networkState&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-networkstate&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;networkState&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute DOMString &lt;A title='Read about this &quot;preload&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-preload&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;preload&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute &lt;A id=timeranges_0 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#timeranges&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;TimeRanges&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; &lt;A title='Read about this &quot;buffered&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-buffered&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;buffered&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  void &lt;A title='Read about this &quot;load&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-load&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;load&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;();
  DOMString &lt;A title='Read about this &quot;canPlayType&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-navigator-canplaytype&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;canPlayType&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;(in DOMString type);

  // ready state
  const unsigned short &lt;A id=dom-media-have_nothing_0 title=dom-media-HAVE_NOTHING style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#dom-media-have_nothing&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;HAVE_NOTHING&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; = 0;
  const unsigned short &lt;A id=dom-media-have_metadata_0 title=dom-media-HAVE_METADATA style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#dom-media-have_metadata&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;HAVE_METADATA&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; = 1;
  const unsigned short &lt;A id=dom-media-have_current_data_0 title=dom-media-HAVE_CURRENT_DATA style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#dom-media-have_current_data&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;HAVE_CURRENT_DATA&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; = 2;
  const unsigned short &lt;A id=dom-media-have_future_data_0 title=dom-media-HAVE_FUTURE_DATA style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#dom-media-have_future_data&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;HAVE_FUTURE_DATA&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; = 3;
  const unsigned short &lt;A id=dom-media-have_enough_data_0 title=dom-media-HAVE_ENOUGH_DATA style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#dom-media-have_enough_data&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;HAVE_ENOUGH_DATA&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; = 4;
  readonly attribute unsigned short &lt;A title='Read about this &quot;readyState&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-readystate&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;readyState&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute boolean &lt;A title='Read about this &quot;seeking&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-seeking&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;seeking&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;

  // playback state
           attribute double &lt;A title='Read about this &quot;currentTime&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-currenttime&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;currentTime&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute double &lt;A title='Read about this &quot;initialTime&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-initialtime&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;initialTime&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute double &lt;A title='Read about this &quot;duration&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-duration&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;duration&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute &lt;SPAN&gt;Date&lt;/SPAN&gt; &lt;A title='Read about this &quot;startOffsetTime&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-startoffsettime&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;startOffsetTime&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute boolean &lt;A title='Read about this &quot;paused&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-paused&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;paused&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute double &lt;A title='Read about this &quot;defaultPlaybackRate&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-defaultplaybackrate&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;defaultPlaybackRate&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute double &lt;A title='Read about this &quot;playbackRate&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-playbackrate&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;playbackRate&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute &lt;A id=timeranges_1 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#timeranges&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;TimeRanges&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; &lt;A title='Read about this &quot;played&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-played&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;played&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute &lt;A id=timeranges_2 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#timeranges&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;TimeRanges&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; &lt;A title='Read about this &quot;seekable&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-seekable&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;seekable&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute boolean &lt;A title='Read about this &quot;ended&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-ended&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;ended&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute boolean &lt;A title='Read about this &quot;autoplay&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-autoplay&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;autoplay&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute boolean &lt;A title='Read about this &quot;loop&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-loop&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;loop&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  void &lt;A title='Read about this &quot;play&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-play&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;play&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;();
  void &lt;A title='Read about this &quot;pause&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-pause&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;pause&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;();

  // media controller
           attribute &lt;SPAN&gt;DOMString&lt;/SPAN&gt; &lt;A title='Read about this &quot;mediaGroup&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-mediagroup&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;mediaGroup&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute &lt;A id=mediacontroller_0 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#mediacontroller&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;MediaController&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; &lt;A title='Read about this &quot;controller&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-controller&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;controller&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;

  // controls
           attribute boolean &lt;A title='Read about this &quot;controls&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-controls&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;controls&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute double &lt;A title='Read about this &quot;volume&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-volume&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;volume&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute boolean &lt;A title='Read about this &quot;muted&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-muted&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;muted&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
           attribute boolean &lt;A title='Read about this &quot;defaultMuted&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-defaultmuted&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;defaultMuted&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;

  // tracks
  readonly attribute &lt;A id=multipletracklist_0 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#multipletracklist&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;MultipleTrackList&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; &lt;A title='Read about this &quot;audioTracks&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-audiotracks&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;audioTracks&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute &lt;A id=exclusivetracklist_0 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#exclusivetracklist&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;ExclusiveTrackList&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; &lt;A title='Read about this &quot;videoTracks&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-videotracks&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;videoTracks&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  readonly attribute &lt;A id=texttrack_2 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#texttrack&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;TextTrack&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;[] &lt;A title='Read about this &quot;textTracks&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-texttracks&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;textTracks&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;;
  &lt;A id=mutabletexttrack_0 style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;https://dev.w3.org/html5/spec-author-view/video.html#mutabletexttrack&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;MutableTextTrack&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt; &lt;A title='Read about this &quot;addTextTrack&quot; reference in the full HTML5 spec.' class=full-spec-link style=&quot;BACKGROUND: none transparent scroll repeat 0% 0%; COLOR: &quot; href=&quot;http://dev.w3.org/html5/spec/video.html#dom-media-addtexttrack&quot;&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;addTextTrack&lt;/FONT&gt;&lt;/U&gt;&lt;/A&gt;(in DOMString kind, in optional DOMString label, in optional DOMString language);
};&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H2&gt;Youtube, Twitch, Pooq&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;실서비스 되고 있는 비디오 플레이어를 살펴보면, Html5 Video 태그로 플레이어 기본 기능을 구현한 것을 알 수 있다.&lt;/P&gt;
&lt;P&gt;각종 버튼과, 광고노출과 같이 플레이어와 겹쳐서 보여지는 부분들은 DIV형태로 플레이어 위에 덧씌어져서 사용자에게 노출하고,&lt;/P&gt;
&lt;P&gt;외부 Html요소를 이용하여 사용자로부터 전달되는 이벤트를 Video Eelement로 전달하는 방식으로 플레이어를 구현했다.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;You Tube&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2155A33D593E50A314&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2155A33D593E50A314&quot; width=&quot;900&quot; height=&quot;384&quot; filename=&quot;youtube.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Twitch&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2616CB39593E075132&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2616CB39593E075132&quot; width=&quot;900&quot; height=&quot;313&quot; filename=&quot;tw.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Pooq&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/247CF735593E07EC31&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F247CF735593E07EC31&quot; width=&quot;900&quot; height=&quot;379&quot; filename=&quot;pooq.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;&lt;/H2&gt;
&lt;H2&gt;Open Source&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;여러 종류의 Html5 Video Player &lt;A class=tx-link href=&quot;http://videosws.praegnanz.de/&quot; target=_blank&gt;비교&lt;/A&gt;1, &lt;A class=tx-link href=&quot;http://html5video.org/wiki/HTML5_Video_Player_Comparison&quot; target=_blank&gt;비교2&lt;/A&gt;, &lt;A class=tx-link href=&quot;http://ourcodeworld.com/articles/read/148/top-7-best-html5-media-player-javascript-plugins&quot; target=_blank&gt;추천&lt;/A&gt;들이 있다.&lt;/P&gt;
&lt;P&gt;다수의 Html5 Video Player 중에서 눈에 뛰는 두가지 오픈소스 플레이어를 소개한다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;두가지 플레이어 모두 플레이어 기본기능을 구현하고 있고, YouTube와 Vimeo완 연동이 가능하다.&lt;/P&gt;
&lt;P&gt;또한 공통적으로 자막, 반응형, 스트리밍, 풀스크린, 다국어와 같은 사용자 편의기능을 포함하고있다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Video.js의 Github Start는&amp;nbsp;16,549개다. Jquery가 45,000개 인것을 감안하면 엄청난 숫자이다. &lt;/P&gt;
&lt;P&gt;사용자가 많은만큼 레퍼런스가 풍부하고, 대부분의 플러그인이 개발되어 있다. &lt;/P&gt;
&lt;P&gt;커스터마이징이 필요없고, 하나의 솔루션처럼 Html5 Video Player가 필요하다면 가장 추천할만한 플레이어다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Plyr의 Github Star는 9,469개다. 유명도에 비해 높은 Star 수를 보유하고 있으며, &lt;/P&gt;
&lt;P&gt;경량화된 Html5 Video Player에 대한 개발자들의 요구를 반영하여 경량과, 커스터마이징에 초점을 맞추어 개발했다.&lt;/P&gt;
&lt;P&gt;비교적 부족한 플러그인과 Owner가 육아에 돌입했다는 단점이 있지만 커스터마이징이 필수인 경우 가장 추천할만한 플레이어다.&amp;nbsp;&lt;/P&gt;&lt;/DIV&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #dbe8fb 1px solid; BORDER-RIGHT: #dbe8fb 1px solid; BORDER-BOTTOM: #dbe8fb 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #dbe8fb 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #dbe8fb&quot;&gt;
&lt;H4&gt;&lt;A class=tx-link href=&quot;https://github.com/videojs/video.js&quot; target=_blank&gt;Video.js&lt;/A&gt;&lt;/H4&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;가장&amp;nbsp;사용자가 많은&amp;nbsp;Video Player Open Source (40만 사이트 이상)&lt;/LI&gt;
&lt;LI&gt;HTML5와 Flash video까지 지원&lt;/LI&gt;
&lt;LI&gt;활발한 PR과 다수의 플러그인&lt;/LI&gt;
&lt;LI&gt;js간 의존성이 높고,&amp;nbsp;파편화(좋은말로 모듈화) 됨&lt;/LI&gt;
&lt;LI&gt;Apache License&lt;/LI&gt;&lt;/UL&gt;
&lt;H4&gt;&lt;A class=tx-link href=&quot;https://github.com/sampotts/plyr&quot; target=_blank&gt;Plyr&lt;/A&gt;&lt;/H4&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;경량, 커스터마이징에 초점을 맞춤&lt;/LI&gt;
&lt;LI&gt;js 파일 하나, 10kb&lt;/LI&gt;
&lt;LI&gt;비교적 부족한 플러그인&lt;/LI&gt;
&lt;LI&gt;Owner가 최근 육아에 전념함&lt;/LI&gt;
&lt;LI&gt;MIT License&lt;/LI&gt;&lt;/UL&gt;&lt;/DIV&gt;
&lt;H2&gt;&lt;/H2&gt;
&lt;H2&gt;Solution&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;유료 솔루션 형태의 Html5 Video Player도 많이 있다.&lt;/P&gt;
&lt;P&gt;&lt;A class=tx-link href=&quot;https://www.theoplayer.com/demo-zone&quot; target=_blank&gt;유료형태의 솔루션&lt;/A&gt;은 HLS(스트리밍)지원과 광고 연동, 사용자 통계, DRM지원, Preview Thumbnail, 360 View, 고객지원과 같은 부가기능을 무기로 가격을 책정한다.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;하지만 Video.js 와 플러그인, hls.js와 같은 오픈소스들로 유료 기능들을 구현할 수 있기 때문에 플레이어만 판매하는 것을 넘어서 &lt;A class=tx-link href=&quot;http://www.bitmovin.com/&quot; target=_blank&gt;인코딩과 CDN, 그리고&amp;nbsp;스트리밍을 위한 서버를 함께 제공해주는 업체&lt;/A&gt;가 많다. 또는 &lt;A class=tx-link href=&quot;http://viblast.com/player/&quot; target=_blank&gt;플레이어를 무료로 풀고 고개지원에만 가격을 책정하는 업체&lt;/A&gt;도 있다.&lt;/P&gt;
&lt;P&gt;자체적으로 스트리밍 서버와 CDN, 인코딩서버를 구축하기 힘든 경우 해당 업체를 사용하면 좋을것 같지만, 최근 &lt;A class=tx-link href=&quot;https://aws.amazon.com/ko/elastictranscoder/&quot; target=_blank&gt;AWS에서 워낙 친절한 솔루션&lt;/A&gt;을 내놓았기 때문에 개발자 관점에서 매력을 찾기는 어려울 것 같다.&lt;/P&gt;&lt;/DIV&gt;
&lt;H2&gt;&lt;/H2&gt;
&lt;H2&gt;OpenSource Issue (DRM, Streaming, Mobile, Ad)&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;오픈소스를 사용하여 Html5 Video Player를 구현할 때 어려운 점이 무엇일까 고민해보았다.&lt;/P&gt;
&lt;P&gt;(유료 솔루션들이 해당 기능을 해결해주고 돈을 받는 것이기 때문에 유료 솔루션의 피처리스트들이 구현 시 어려운 점이었다.)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;HLS Streaming : hls.js를 사용하면 된다.&lt;/P&gt;
&lt;P&gt;DRM : hls.js를 사용하면 되지만, 스트리밍이 아닌경우 생각해봐야할 문제.&lt;/P&gt;
&lt;P&gt;Mobile : 반응형 개발로 Web View 재생을 하면 되지만, 성능이 받쳐줄지는 미지수. 성능이슈라면 유료 솔루션도 어쩔수 없다.&lt;/P&gt;
&lt;P&gt;Ad : 광고를 심는 시점과 고객 행동 데이터를 수집해야한다. 광고 노출기능은 Video.js에서&lt;A class=tx-link href=&quot;https://github.com/videojs/videojs-contrib-ads&quot; target=_blank&gt; videojs-contrib-ads라는 플러그인 형태로 구현해 두었지만&lt;/A&gt;, 광고 전환율, 사용자당 클릭 퍼센트와 같은 통계데이터 수집은 따로 구현해야할 부분이다. 이 부분은 플레이어 자체의 기능이라기보다 서비스 플랫폼의 관점으로 바라봐야 할 것 같다.&lt;/P&gt;&lt;/DIV&gt;</description>
      <category>JAVASCRIPT</category>
      <category>html5</category>
      <category>html5 video player</category>
      <category>javascript</category>
      <category>javascript video player</category>
      <category>Player</category>
      <category>plyr</category>
      <category>Video</category>
      <category>videojs</category>
      <category>web video player</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/11</guid>
      <comments>https://bkim.tistory.com/11#entry11comment</comments>
      <pubDate>Tue, 6 Jun 2017 19:54:39 +0900</pubDate>
    </item>
    <item>
      <title>Angular Change Detection &amp;amp; Zone.js</title>
      <link>https://bkim.tistory.com/10</link>
      <description>&lt;H2&gt;Change Detection 란 무엇인가?&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;&lt;STRONG&gt;Change Detection&lt;/STRONG&gt;(이하 CD)는 뷰와 모델을 동기화 할 수 있도록&amp;nbsp;컴포넌트의 변경을 감지하고&amp;nbsp;값을 동기화 하는&amp;nbsp;프로세스다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Angular JS (1.x)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;뷰단의 변경을 감지하는 것 뿐만 아니라, 비동기로 돌아가는&amp;nbsp;자바스크립트(ajax, setTimeout 등..)가 데이터&amp;nbsp;변경하는&amp;nbsp;시점을 감지하여 모델의 변경의 뷰단에 반영해야 하는데 Angular 1에서는 이런 로직을 Digest Loop로 구현 했었다.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Digest Loop로&amp;nbsp;감시할 대상을 지정하기 위해&amp;nbsp;scope마다 watcher을 등록하여 감지할 목록들을 만들어야 했는데 이런 상황 때문에, 데이터의 변경을 감지하기 위해서는 Angular 도구만을 사용해야 했다. ajax call 또는 click 같은 이벤트도 $http와 ng-click으로 구현해야만 모델 변경이 감지되었다.&lt;/P&gt;
&lt;P&gt;이를 보완하기 위해 명시적 호출($diest, $apply, $timeout)을 지원했지만 개발자가 직접호출해야한다는 이질감이 있었다.&lt;/P&gt;
&lt;P&gt;또한 Angular 1은&amp;nbsp;양방향 데이터 바인딩으로 구현했기 때문에 watcher들이 늘어날 수록 Digest Loop은 걷잡을 수 없이 혼란스러워졌다.&lt;/P&gt;&lt;/DIV&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;&lt;STRONG&gt;Angular&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Angular2에서는 $scope기능을 없애고 Zone.js를 이용하여&amp;nbsp;CD를 구현하였는데, Zone.js 덕분에 Angular 도구 뿐만 아니라, 순수 자바스크립트로 컴포넌트를 구성할 수 있게 되었다. 또한 Angular 2는 단방향 바인딩을 구현하였기 때문에 (ngModel을 사용해서 양방향 바인딩을 구현할때도 데이터의 흐름은 단방향) CD는 어플리케이션 전체를 변경할 필요 없이 데이터가 바인딩 되어있는 곳만 변경을 감지하고 Angular2는 변경된 부분만 다시 그려주면 되었다. 이를 통해 Angular는 성능을 높일 수 있었고 강제되던 Angular 도구들을 제거할 수 있었다.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 690px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2277DC34592FA86509&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2277DC34592FA86509&quot; width=&quot;690&quot; height=&quot;401&quot; alt=&quot;Figure: File Structure&quot; filename=&quot;angular1-vs-angular2.jpg&quot; filemime=&quot;image/jpeg&quot; original=&quot;yes&quot;/&gt;&lt;span class=&quot;cap1&quot; style=&quot;display: block; max-width:100%; &quot;&gt;Figure: File Structure
출처 - https://angular-2-training-book.rangle.io&lt;/span&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;H2&gt;어떻게 변화를 감지하는가? (Zone.js - &lt;A class=tx-link href=&quot;https://www.youtube.com/watch?v=CUxD91DWkGM&quot; target=_blank&gt;동영상&lt;/A&gt;)&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;Angular는 Angular도구가 아닌 순수 자바스크립트로 변경한 데이터 변경 또한 감지 할 수 있다고 했다.&lt;/P&gt;
&lt;P&gt;우리가 웹에서&amp;nbsp;ajax로 데이터로 가져오거나, Timer로 함수를 실행하거나, click 이벤트를 발생시키는것은 모두 비동기로 이루어지는데 사용자가 명시적으로 호출하지 않고도 어떻게 Angular는 어플리케이션 상태 변화를 감지할 수 있을까?&lt;/P&gt;
&lt;P&gt;답은 Zone.js에 있었다. (Angular는 자체적인 Zone을 가지고 있고 ngZone이라고 한다.) &lt;/P&gt;
&lt;P&gt;Zone.js는 JAVA의 ThreadLocal 개념과 비슷해서 각각의 비동기 기능에서 kick on과 kick off를 설정하지 않아도 Zone이 이를 감지하여 후킹할수 있게 해준다. &lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;IFRAME height=300 src=&quot;//jsfiddle.net/nbgrz4hy/embedded/js,html,css,result/dark/&quot; frameBorder=0 width=&quot;100%&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/IFRAME&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;위&amp;nbsp;코드를 실행해보면 콘솔 창에 다음과 같이 나타단다.&lt;/P&gt;
&lt;P&gt;1번에서 click event listener가 등록된것을&lt;/P&gt;
&lt;P&gt;2번에서 setTimeout이 발생하여 Invoike 한것을 상세하게 알 수 있다.&lt;/P&gt;
&lt;P&gt;이렇게 Zone.js는 비동기 코드들을 컨트롤하면서 사용자에게 편리한 후킹인터페이스를 제공해주는 것이고, &lt;/P&gt;
&lt;P&gt;Angular는 ngZone을 이용해서 컴포넌트의 변화를 감지하는 것이다.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 877px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/276CFD3A592FC2A93F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F276CFD3A592FC2A93F&quot; width=&quot;877&quot; height=&quot;628&quot; filename=&quot;console.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Angular에서 구현된 소스는 다음과 같다.&lt;/P&gt;&lt;PRE style=&quot;FONT-SIZE: 9.8pt; FONT-FAMILY: 'Lucida Sans Typewriter'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;this&lt;/SPAN&gt;.zone.onMicrotaskEmpty&lt;br /&gt;    .subscribe(() =&amp;gt; {&lt;br /&gt;        &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;this&lt;/SPAN&gt;.zone.run(() =&amp;gt; &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;this&lt;/SPAN&gt;.tick()&lt;br /&gt;    })&lt;br /&gt;})&lt;br /&gt;&lt;br /&gt;&lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;tick&lt;/SPAN&gt;()&lt;br /&gt;{&lt;br /&gt;    &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;this&lt;/SPAN&gt;.changeDetectorsRefs&lt;br /&gt;        .forEach((ref) =&amp;gt; ref.detectChanges())&lt;br /&gt;}&lt;/PRE&gt;
&lt;H2&gt;어떻게 변경하는가?&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;그렇다면 앞서 ngZone이 감지한 변화를 Angular는 어떻게 View에 적용할까?&lt;/P&gt;
&lt;P&gt;Angular의 컴포넌트들은 각자 자신만의 CD를 가지고 있어서,&amp;nbsp;각자&amp;nbsp;CD&amp;nbsp;수행하고 컨트롤할 수 있다. 예를 들어 클릭 이벤트가 발생하면, Zone.js가 이벤트를 감지하여 알려주고 Angular는 CD를 실행한다. 이 때 컴포넌트는 각자 자신의 CD를 가지고 있고 컴포넌트는 트리구조로 이루어져 있기 때문에 CD의 구조도 방향이 있는&amp;nbsp;트리구조로 구성된다.&amp;nbsp;방향성이 있는 트리구조 때문에 CD는 항상 TOP에서 ROOT로 전파된다.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 819px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/235317445931086004&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F235317445931086004&quot; width=&quot;819&quot; height=&quot;477&quot; alt=&quot;http://pascalprecht.github.io/slides/angular-2-change-detection-explained/#/59&quot; filename=&quot;7f3a8ca6-8fc3-11e6-937a-958f5d05adab.gif&quot; filemime=&quot;image/gif&quot; original=&quot;yes&quot;/&gt;&lt;span class=&quot;cap1&quot; style=&quot;display: block; max-width:100%; &quot;&gt;http://pascalprecht.github.io/slides/angular-2-change-detection-explained/#/59&lt;/span&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;Angular 컴포넌트들은 자신만의 Change Detector를 가진다?&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;Runtime에 Angular는 각&amp;nbsp;컴포넌트마다 자신이 가진 속성들에 대하여&amp;nbsp;Change Detector&amp;nbsp;클래스를 생성한다.&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;Change detector들은 컴포넌트의 각 속성에대한 Old Value를 가지고 있기때문에 독립적으로 자신의 컴포넌트에 대한 변경 여부를 확인 할 수 있고,&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;감지 속도를 높이기 위해 개발자가 전략을 작성하거나 속성값 등을 전달 할 수 있다.&lt;/P&gt;&lt;/DIV&gt;&lt;PRE style='FONT-SIZE: 9.8pt; FONT-FAMILY: &quot;Lucida Sans Typewriter&quot;; COLOR: rgb(169,183,198); BACKGROUND-COLOR: rgb(43,43,43)'&gt;&lt;P&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;/**&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt; * &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;@license&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt; &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;* Copyright Google Inc. All Rights Reserved.&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt; *&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt; * Use of this source code is governed by an MIT-style license that can be&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt; * found in the LICENSE file at https://angular.io/license&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt; */&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;/**&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt; * &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;@stable&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt; &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;*/&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;export declare abstract class &lt;/SPAN&gt;ChangeDetectorRef {&lt;br /&gt;   &lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt; &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;abstract &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(255,198,109)&quot;&gt;markForCheck&lt;/SPAN&gt;(): &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;void&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(204,120,50)&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(204,120,50)&quot;&gt;    &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;/**&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;     * Detaches the change detector from the change detector tree.&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;     */&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;    &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;abstract &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(255,198,109)&quot;&gt;detach&lt;/SPAN&gt;(): &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;void&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(204,120,50)&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(204,120,50)&quot;&gt;    &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;/**&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;     * Checks the change detector and its children.&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;     */&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;    &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;abstract &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(255,198,109)&quot;&gt;detectChanges&lt;/SPAN&gt;(): &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;void&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(204,120,50)&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(204,120,50)&quot;&gt;    &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;/**&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;     * Checks the change detector and its children, and throws if any changes are detected.&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;     &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;*/&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;    &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;abstract &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(255,198,109)&quot;&gt;checkNoChanges&lt;/SPAN&gt;(): &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;void&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(204,120,50)&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(204,120,50)&quot;&gt;    &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;/**&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;     * Reattach the change detector to the change detector tree.&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;     &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;*/&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(98,151,85); FONT-STYLE: italic&quot;&gt;    &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;abstract &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(255,198,109)&quot;&gt;reattach&lt;/SPAN&gt;(): &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: rgb(204,120,50)&quot;&gt;void&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: rgb(204,120,50)&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;}&lt;br /&gt;&lt;/P&gt;&lt;/PRE&gt;
&lt;H2&gt;Change Detection을 빠르게&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;그렇다면 어떻게 Chage Detection을 효율적으로 실행할 수 있을까? 
&lt;P&gt;앞서 설명했듯이 CD는 Runtime시&amp;nbsp;각 컴포넌트마다&amp;nbsp;생성되기 때문에 다양한 형태를 가질 수 있다. 각 컴포넌트의&amp;nbsp;구조에 맞게 CD 클래스를 정의 하고 생성하기 때문에, CD가 감시해야할 대상을 줄이면 성능을 높일 수 있다. Angular는 CD가 감시해야 할 대상을 줄이기 위해 Immutable 객체와 Observable 객체를 알아?보고 감시 대상에서 제외해&amp;nbsp;할 수 있는데, 이런 최적화는 Angular의&amp;nbsp;&lt;A class=tx-link href=&quot;https://angular.io/docs/ts/latest/api/core/index/ChangeDetectionStrategy-enum.html&quot; target=_blank&gt;OnPush &lt;/A&gt;전략(컴포넌트에 바인딩된 Input 값의 변화가 없는 경우에는 Subtree 에 대해 Change Detection을 하지 않음)으로 설정하여&amp;nbsp;처리한다. &lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;Immutable&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;Immutable 객체는 값의 변화가 없음을 보장한다.&amp;nbsp;새로운 값을 지정하고 싶으면 객체를 변경하는 것이 아니라 새로 생성 해야만한다.&lt;/P&gt;
&lt;P&gt;객체를 새로 생성한다는 것은 Angular 입장에서 값(상태) 비교가 필요 없다는 것을 뜻한다.&amp;nbsp;Immutable 객체를 사용하는&amp;nbsp;바인딩된 컴포넌트들은&amp;nbsp;변경된 객체의 상태를 비교해 볼 필요 없이 객체의 레퍼런스만으로 변화를 감지할 수 있다.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;(Javascript&amp;nbsp;Immutable lib들을 이용하여 손쉽게 Immutable 객체를 생성해 볼&amp;nbsp;수 있는다. &lt;A class=tx-link href=&quot;https://facebook.github.io/immutable-js/&quot; target=_blank&gt;Immutable.js &lt;/A&gt;&lt;A class=tx-link href=&quot;https://facebook.github.io/immutable-js/&quot; target=_blank&gt;Gith&lt;/A&gt;&lt;A class=tx-link href=&quot;https://facebook.github.io/immutable-js/&quot; target=_blank&gt;ub&lt;/A&gt;)&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2445E03E59310B0E24&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2445E03E59310B0E24&quot; width=&quot;900&quot; height=&quot;614&quot; alt=&quot;http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html&quot; filename=&quot;1.PNG&quot; filemime=&quot;image/jpeg&quot; original=&quot;yes&quot;/&gt;&lt;span class=&quot;cap1&quot; style=&quot;display: block; max-width:100%; &quot;&gt;http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html&lt;/span&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;Observable&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;관찰할 수 있는, 식별할 수 있는 객체를 의미한다. 관찰할 수 있는 객체를 구독(subscribe)하면서 값을 참조하는 방법이다.&lt;/P&gt;
&lt;P&gt;예를 들어 다음과 같은 코드가 있을 때, firstName만 변경하여도 fullName까지 함께 변경 되는 것이다.&lt;/P&gt;&lt;/DIV&gt;&lt;PRE style=&quot;FONT-SIZE: 9.8pt; FONT-FAMILY: 'Lucida Sans Typewriter'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;var &lt;/SPAN&gt;firstName = Observable(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'BK'&lt;/SPAN&gt;)&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;var &lt;/SPAN&gt;lastName = Observable(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'KIM'&lt;/SPAN&gt;)&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;var &lt;/SPAN&gt;fullName = Observable(&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;function &lt;/SPAN&gt;() {&lt;br /&gt;    &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;return &lt;/SPAN&gt;firstName.value + &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;' ' &lt;/SPAN&gt;+ lastName.value&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;})&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P&gt;Angular에서는 Immutable 객체&amp;nbsp;반대 방식으로 CD를 생략한다. Immutable 객체의 레퍼런스 참조만으로 CD를 생략할 수 있었다면 반대로 Observabel 객체는 값의 변경점에서 이벤트를 발생시켜서&amp;nbsp;TOP CD까지 변경을 전파한다. 따라서 Angular는&amp;nbsp;ROOT에서 TOP으로 가는&amp;nbsp;길목에 있는 CD만 수행하면 되는 것이다. 이때 OnPush전략을 함께 사용하면 Observable 객체의 레퍼런스는 변경되지 않기 때문에, 이벤트 컴포넌트 Subtree의&amp;nbsp;CD가 생략 된다. 하위 컴포넌트들도 함께 업데이트 해야한다면 디텍터의 markForCheck()라는 API를 이용하여 Subtree까지 CD를 수행 할 수 있다.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 744px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2610074F5931126101&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2610074F5931126101&quot; width=&quot;744&quot; height=&quot;517&quot; alt=&quot;http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html&quot; filename=&quot;22.gif&quot; filemime=&quot;image/gif&quot; original=&quot;yes&quot;/&gt;&lt;span class=&quot;cap1&quot; style=&quot;display: block; max-width:100%; &quot;&gt;http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html&lt;/span&gt;&lt;/span&gt;&lt;/P&gt;
&lt;H2&gt;마치며&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;AngularJs 1.x에서 Angular 2로 넘어오면서 가장 관심이&amp;nbsp;갔던 부분은 성능이었다.&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;Change Detection에 대해서 자세히 알아보기 전까진&amp;nbsp;ReactJS의 Virtual DOM과 비슷한 방식이라 생각했었는데, 깊이 들여다보니 Framewrok로서 장점을 잘 이용한 것 같다. 성능 저하와 복잡도 상승의 주 원인이던 양방향 바인딩을 없애고, Zone.js를 도입 함으로써 라이브러리 사용에 비해 자유롭지 못한&amp;nbsp;Framework의 단점을 보완하려 한 부분도&amp;nbsp;흥미로웠다.&amp;nbsp;들여다 볼수록 매력있는 Angular지만 제대로 사용하지 않으면 이러한 장점들의 존재조차 모르고 사용하게 될것이란 게 두렵기도 하다.&amp;nbsp;&lt;/P&gt;&lt;/DIV&gt;
&lt;H2&gt;참조&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;Change Detection In Angular&amp;nbsp;: &lt;A href=&quot;https://vsavkin.com/change-detection-in-angular-2-4f216b855d4c&quot;&gt;https://vsavkin.com/change-detection-in-angular-2-4f216b855d4c&lt;/A&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;Change Detection : &lt;A href=&quot;https://angular-2-training-book.rangle.io/handout/change-detection/&quot;&gt;https://angular-2-training-book.rangle.io/handout/change-detection/&lt;/A&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;Angular Change Detection Explained : &lt;A href=&quot;https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html&quot;&gt;https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html&lt;/A&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;OnPush 동작 방식 이해 : &lt;A href=&quot;https://jongmoon.github.io/blog/2017/02/13/ng-onpush-mechanism/&quot;&gt;https://jongmoon.github.io/blog/2017/02/13/ng-onpush-mechanism/&lt;/A&gt;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;자바스크립트 프레임워크 소개 2 : Angulr2 - &lt;A href=&quot;http://meetup.toast.com/posts/98&quot;&gt;http://meetup.toast.com/posts/98&lt;/A&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style=&quot;FLOAT: none; TEXT-ALIGN: center; CLEAR: none&quot;&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <category>ANGULAR</category>
      <category>angular</category>
      <category>Angular2</category>
      <category>Change detection</category>
      <category>zone</category>
      <category>zone.js</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/10</guid>
      <comments>https://bkim.tistory.com/10#entry10comment</comments>
      <pubDate>Thu, 1 Jun 2017 12:34:24 +0900</pubDate>
    </item>
    <item>
      <title>Javscript Framework와 Library (Angular VS React.js VS VanillaJS)</title>
      <link>https://bkim.tistory.com/9</link>
      <description>&lt;H2&gt;결론&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: rgb(238,238,238) 1px solid; BORDER-RIGHT: rgb(238,238,238) 1px solid; BORDER-BOTTOM: rgb(238,238,238) 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: rgb(238,238,238) 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: rgb(238,238,238)&quot;&gt;
&lt;P&gt;JavaScript개발시 어떤 프레임워크 또는 라이브러리는 사용할것인가? 라는 질문에 대답하기 위해 기술조사를 했다.&lt;/P&gt;
&lt;P&gt;사용할&amp;nbsp;기술을 선택할 때는&amp;nbsp;&amp;nbsp;언제나 트레이드 오프가 발생한다.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;따라서 개발하려고 하는 서비스와 팀의 규모를 고려해서 결정 하는 것이, 트렌드와 유행에따라 결정하는것보다 타당하다 생각한다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;기술조사를 마치고 느낀점은 Angular는 개발자의 자유도를 제한하는 대신, 우리가 마주할 수 있는 이슈에 대하여 기본적인&amp;nbsp;방법을 제시해고&amp;nbsp;있었고,&lt;/P&gt;
&lt;P&gt;React는 스스로 라이브러리임을 밝히며 몸집을 최소화하며 개발자의 선택을 존중하고 있었다. 개발자의 자유도를 제한하지 않는면에서 잘나가는? 분야에서 조예가 깊은? 개발자는 React Family를 좋아하겠다는 생각을 여러번 했다. 실제로 기술조사를 하면서 React를 추천하는 곳에서&amp;nbsp;geek함과 개발자스러운 냄새를&amp;nbsp;맡을 수 있었다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;부족한 견해일지 모르지만 서버개발 프레임워크와 비교해보았을 때 Angular를 보면서 Spring같다는&amp;nbsp;생각을, React Family를 보면서 Node.js 같다는 생각을 했다. 또한 진정으로 POJO와 닮은&amp;nbsp;Vanilla JS의 간단한 페이지를 돌아보며 이것 또한 좋은 방법 같았다. Jquery 또한&amp;nbsp;여전히 사용성에서 1등을 고수하고 있었으며,&amp;nbsp;사용 추세가 전혀 줄어들지 않고 있었다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;다만 우리가 Spring을 사용하듯이, 팀단위로 일정한 수준 이상의 JavaScript 생산성과 품질을 유지하려면 Angular의 프레임 안에서 개발해나가는게 좋을 것 같다. 개발자에게 주어지는 자유도가 높을수록 성능은&amp;nbsp;높아질 수 있지만, 유지 보수와 협업의 관점에서의 성능은&amp;nbsp;어플리케이션의 규모가 커질수록 낮아질 것이다.&amp;nbsp;&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;만약 우리가 Front개발에 익숙하지 않은 팀이라면 Angular를, Front개발에 익숙한 팀이라면 React Family를 사용하는 것이 좋겠다.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;소규모의 팀이거나 규모가 작은 서비스는 Front개발의 숙련도를 떠나&amp;nbsp;React Family를 이용하는것이 좋을 것 같다.&lt;/B&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;H2&gt;Framework&lt;/H2&gt;
&lt;P&gt;프레임워크란 무엇일까? 자바스크립트 프레임워크를 비교하기 전에 프레임워크에 대한 정의부터 분명히 해야겠다.&lt;/P&gt;
&lt;P&gt;GoF의 디자인패턴 저자 랄프존슨은 &quot;프레임워크란 소프트웨어의 구체적인 부분에 해당하는 설계와 구현을 재사용이 가능하게끔 일련의 협업화된 형태로 클래스를 제공하는 것&quot; 라고 말한다. 혹자는 디자인 패턴 + 라이브러리 = 프레임워크라고 주장한다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;다양한 프레임워크가 존재하는 만큼 다양한 의미를 포함하고 있지만, 자바스크립트 프레임워크는 Inversion of control을 가능케하고&amp;nbsp;Modularity, Reusability, Extensibility 를 높이기 위한 목적을 가진&amp;nbsp;라이브러리 + 구조화 된 뼈대의 조합이라고 생각하면 좋을 것 같다. 우리가 흔히 사용하는 Jquery는 뼈대를 제공하지 않고 라이브러리만 제공하기때문에 프레임워크라고 부르지 않는다. Jquery를 사용해서&amp;nbsp;MVC 패턴을 입히면 그것은 프레임워크라 부를 수 있을 것이다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;최근 JavaScript가 사용되는 분야가 많아지고 인기가 높아지면서 오픈소스로 개발되는 자바스크립트 프레임워크들 또한 다양해지고 있다.&lt;/P&gt;
&lt;P&gt;그 중에서 Angular 와 React를 비교해보고 이러한 상황을 비꼬는 듯한 용어인 Vanilla JS에 대하여 알아보자.&lt;/P&gt;
&lt;H2&gt;Angular&lt;/H2&gt;
&lt;P&gt;Angular는 MVC&amp;nbsp;Framework로 최근 4.0버전을 출시했다. AngularJs는 1.x 버전을 지칭하고 Angular는 2.0 이후 버전을 지칭하는데, 1버전과 2버전은 패러다임의 변화가 있었고, 2버전 이후부터는 하위버전 호환을 유지하고있다. AngularJs에서 성능 문제의 주요원이었던 2 way data binding을 Angular에서는 빌트인으로 제공하지 않으며 서로 호환되지도 않음으로 분리해서 보아야 한다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;Angular는 구글 자체적으로 개발하던 AtScript를 사용하려 했으나, Microsoft와 협력하여 TypeScript를 채택했다.&lt;/P&gt;
&lt;P&gt;한편에선 Facebook의 React와 달리&amp;nbsp;구글이 Angular를 사용하는 비중이 낮다는 점을 우려하고 있다. (YouTube를 새로 개편할 때 &lt;A class=tx-link href=&quot;https://www.polymer-project.org/&quot; target=_blank&gt;Polymer&lt;/A&gt; 사용)- &lt;A class=tx-link href=&quot;http://d2.naver.com/helloworld/7229119&quot; target=_blank&gt;링크1&lt;/A&gt;, &lt;A class=tx-link href=&quot;http://react-etc.net/entry/youtube-is-being-rebuilt-on-web-components-and-polymer&quot; target=_blank&gt;링크2&lt;/A&gt;&lt;/P&gt;
&lt;H2&gt;React.js&lt;/H2&gt;
&lt;P&gt;UI 컴포넌트를 만들기 위한 라이브러리로, UI 컴포넌트만을 지원함으로 지원하는 범위가 작지만 다향한 조합으로 사용 할 수 있다.&lt;/P&gt;
&lt;P&gt;React.js로&amp;nbsp;Angular의 directives를 구현하여 프레임워크를 구성할 수 있지만, 보통 Redux를 이용하여 프레임워크를 구축한다.&lt;/P&gt;
&lt;P&gt;JavaScript와 TypeScript를&amp;nbsp;지원하지만 JSX라는 ECMAScript 친화적인 XML 문법을 사용할 것을 추천한다.&lt;/P&gt;
&lt;H2&gt;VanillaJS&lt;/H2&gt;
&lt;P style=&quot;FLOAT: left; CLEAR: both&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 390px; MARGIN-RIGHT: 10px; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2601FD3E592298551D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2601FD3E592298551D&quot; width=&quot;390&quot; height=&quot;287&quot; filename=&quot;579736_406258776135201_1565782083_n.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;MARGIN-RIGHT: 10px&quot;/&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;VanillaJS는 자바스크립트 라이브러리와 프레임워크 홍수를 풍자하는 단어이다.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Java에서 POJO와 비슷한 개념이라 볼 수 있다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;순수한 JavaScript만을 이용하여 구현한?(구현해야 할)&amp;nbsp;프레임워크다.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;별도의 라이브러리 없이 순수한 JavaScript만을 사용했기 때문에 가장 빠르고, 가벼운 장정이 있다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;&lt;A class=tx-link href=&quot;http://vanilla-js.com/&quot; target=_blank&gt;http://vanilla-js.com/ &lt;/A&gt;에서 사용하고 싶은 컴포넌트를 선택 후 다운받아 소스를 열어보면 그 의미를 더욱 잘 알 수 있다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;H2&gt;Angular VS React.js ? (2016 데뷰 정리 -&amp;nbsp;&lt;A class=tx-link href=&quot;http://serviceapi.rmcnmv.naver.com/flash/outKeyPlayer.nhn?vid=AF21005C8C167BEA4B5EA26D7F39FD5EFBC1&amp;amp;outKey=V124e1e36bca5003c98025508428f425ce66c2a197176d9421f195508428f425ce66c&amp;amp;controlBarMovable=true&amp;amp;jsCallable=true&amp;amp;skinName=tvcast_white&quot; target=_blank&gt;영상&lt;/A&gt;&amp;nbsp;,&amp;nbsp;&lt;A class=tx-link href=&quot;https://www.slideshare.net/deview/114angularvs-react&quot; target=_blank&gt;발표자료&lt;/A&gt;)&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: rgb(238,238,238) 1px solid; BORDER-RIGHT: rgb(238,238,238) 1px solid; BORDER-BOTTOM: rgb(238,238,238) 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: rgb(238,238,238) 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: rgb(238,238,238)&quot;&gt;
&lt;P&gt;위에서 설명했듯이 Angular는 프레임워크고 React.js는 라이브러리다.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;둘을 1:1로 비교하는것은 무리가 있고 Angular VS React Family(React.js + Redux + React router + Babel) 정도로 비교해야할 것이다.&lt;/P&gt;
&lt;P&gt;2016년 데뷰발표자료에&amp;nbsp;사견을 더해 둘을 비교해 봤다.&lt;/P&gt;&lt;/DIV&gt;
&lt;H4&gt;1. 성능&lt;/H4&gt;
&lt;P&gt;https://github.com/CoderK/js-framework-benchmark 로 성능 평가 해본 결과&amp;nbsp;&lt;/P&gt;
&lt;TABLE class=txc-table style=&quot;BORDER-TOP: medium none; FONT-FAMILY: ; BORDER-RIGHT: medium none; BORDER-COLLAPSE: collapse; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none&quot; cellSpacing=0 cellPadding=0 width=864 border=0 sans-serif;font-size:13px?=&quot;&quot; 고딕?,=&quot;&quot; 맑은=&quot;&quot;&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid; BORDER-LEFT: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid; BORDER-LEFT: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Angular&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;React&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;Vanilla&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid; BORDER-LEFT: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;상대 시간&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid; BORDER-LEFT: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;2.12&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;2.00&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;1.00&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid; BORDER-LEFT: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;메모리 사용량&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid; BORDER-LEFT: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;2.67&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;1.79&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;1.00&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;의미있는 속도차이는 없었음. 엔터프라이즈급 서비스 개발을 위해서 생산성에 좀 더 초점을 두어야 할것 같다.&lt;/P&gt;
&lt;P&gt;학습 비용은 비슷하다고 생각함.&lt;/P&gt;
&lt;H4&gt;2. 언어 생산성&lt;/H4&gt;
&lt;P&gt;최근 Angular CLI 까지 나오면서 개발 환경과 학습 비용은 Angular가 낮다고 생각한다.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;또한, Angular가 사용되는 곳이&amp;nbsp;많아지면서 (웹앱, 앱, 데으크탑 앱) 사용성도 증가되고 있다.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;TABLE class=txc-table style=&quot;BORDER-TOP: medium none; FONT-FAMILY: ; BORDER-RIGHT: medium none; BORDER-COLLAPSE: collapse; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none&quot; cellSpacing=0 cellPadding=0 width=864 border=0 sans-serif;font-size:13px?=&quot;&quot; 고딕?,=&quot;&quot; 맑은=&quot;&quot;&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 431px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Angular&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 432px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;React&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 65px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 431px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;&amp;nbsp;구글은 웹표준을 철저히 지키는 회사.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;&amp;nbsp;새로운 언어를 배운다는 개념보다 Next Es 라고 생각하자&lt;/LI&gt;
&lt;LI&gt;&amp;nbsp;구글이 만든게 표준이 아니면 표준을 추가하려고한다...?!&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 65px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 432px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;&amp;nbsp;TypeScript는 지나친 비용을 야기한다.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;&amp;nbsp;타입 체커 라이브러리인 FLOW면 충분하다.&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 863px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot; colSpan=2&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;&amp;nbsp;언어 생산성 측면에서&amp;nbsp;JavaScript 언어의 한계가 존재&amp;nbsp;했고 TypeScript가 탄생했다.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;&amp;nbsp;Angular 와 React 모두 TypeScript를 사용할 수 있지만, React는 타입을 지정해 주는 체커형태 라이브러리인 FLOW를 더 많이 사용하는 편&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;H4&gt;3. 컴포넌트&lt;/H4&gt;
&lt;TABLE class=txc-table style=&quot;BORDER-TOP: medium none; FONT-FAMILY: ; BORDER-RIGHT: medium none; BORDER-COLLAPSE: collapse; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none&quot; cellSpacing=0 cellPadding=0 width=864 border=0 sans-serif;font-size:13px?=&quot;&quot; 고딕?,=&quot;&quot; 맑은=&quot;&quot;&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 431px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Angular&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 432px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;React&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 103px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 431px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;Angular는 HTML 과 JS CSS 를 잘 분리했고 CSS 캡슐화를 내부적으로 지원해서 높은 이식성과 재사용성을 보장한다.&lt;/LI&gt;
&lt;LI&gt;JSX를 쓰면 마크업이 JS안으로 들어가는 형태. 코드를 실행하기 전까지 마크업 미리보기가 안된다. 또한 자바스크립트를 모르는 마크업 개발자와 협업할 경우 협업 자체가 매우 어렵다.&lt;/LI&gt;
&lt;LI&gt;Angular는 표준 HTML에 디렉티브를 확장해나가는 개념이라 기존 HTML 문법을 그대로 사용할 수 있다.(React는&amp;nbsp;className, defaultValue 같은 문법 사용)&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 103px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 432px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;React역시 Webpack를 사용하면 CSS 캡슐화를 지원할 수 있지만 네이티브로 지원하지 않은 것은 조금 아쉬운 부분인건 사실.&lt;/LI&gt;
&lt;LI&gt;협업이 어려운점은 동의한다. 하지만 Angular도 Html에 논리코드(디렉티브)를 끼워넣어야 함으로 구조 안에 행위를 집어 넣는 순간 순수하지 못하다.&lt;/LI&gt;
&lt;LI&gt;사실 구조와 기능을 분리할 수 없다. 그래서 통합하는 것을 목적으로 했고, JSX 는 기존 javascript에서 DOM을 생성하던 것의 단점을 보안하고 가독성을 높인 결과물이다.&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 863px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot; colSpan=2&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;&amp;nbsp;컴포넌트 = HTML&amp;nbsp;+ JS + CSS&lt;/LI&gt;
&lt;LI&gt;&amp;nbsp;CSS분리에 대해서는 동의하지만 JSX의 존재에 대하여선 대립&amp;nbsp;&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;H4&gt;4. 데이터 동기화&lt;/H4&gt;
&lt;TABLE class=txc-table style=&quot;BORDER-TOP: medium none; FONT-FAMILY: ; BORDER-RIGHT: medium none; BORDER-COLLAPSE: collapse; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none&quot; cellSpacing=0 cellPadding=0 width=864 border=0 sans-serif;font-size:13px?=&quot;&quot; 고딕?,=&quot;&quot; 맑은=&quot;&quot;&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 432px; BORDER-BOTTOM: #ccc 1px solid; BORDER-LEFT: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Angular&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 432px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;React&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 86px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 432px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;Angular의 경우 양방향 바인딩으로 성능이슈가 있었지만 Angular2와 React는 상당히 닮아있고 성능부분에서도 비슷해짐.&lt;/LI&gt;
&lt;LI&gt;Angular는 React의 Virtual DOM을 보고? 체인지 디렉터라는 것을 만들었다. 마찬가지로 모델이 바뀌면&amp;nbsp;트리구조의 DOM을 훑으면서 달라진 부분만 다시 그린다.&lt;/LI&gt;
&lt;LI&gt;Angular는 조금 더 나아가서 Zone(실행영역)이란 것을 이용해서 DOM 변경시 setState, setValue를 개발자가 명시하지 않아도&amp;nbsp;자동으로 모델을 변경시켜준다. (React 는 DOM -&amp;gt; Model 은 명시해줘야함)&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 86px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 432px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;React는 Virtual DOM을 이용하여 모델이 바뀌면 새로운 Virtual DOM을 그리고 기존 Virtual DOM 과 비교해서 Diff 된 부분만 새로 그려준다.&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 863px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot; colSpan=2&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;뷰와 모델의 분리 후 데이터 동기화 문제 등장.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;Angular의 경우 양반향 바인딩으로 성능 이슈가 있었지만, Angular2로 넘어오면서 개선된 상태&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;H4&gt;5. 비동기 처리&lt;/H4&gt;
&lt;TABLE class=txc-table style=&quot;BORDER-TOP: medium none; FONT-FAMILY: ; BORDER-RIGHT: medium none; BORDER-COLLAPSE: collapse; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none&quot; cellSpacing=0 cellPadding=0 width=864 border=0 sans-serif;font-size:13px?=&quot;&quot; 고딕?,=&quot;&quot; 맑은=&quot;&quot;&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 431px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Angular&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 432px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;React&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 120px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 431px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;비동기 처리를 위해 RxJS를 품었다. ZONE을 이용한 DOM -&amp;gt; MODEL 로 데이터 전송처럼 Angular 자체적으로 RxJS는 잘 품었다.&lt;/LI&gt;
&lt;LI&gt;Javascript가 가진 다른 대안도 많은 와중에 왜 RxJS를 품은 것인지는 더 지켜봐야할 일&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 120px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 432px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;&amp;nbsp;React는 라이브러리인 만큼 Angular보다 자유롭게 비동기 라이브러리를 쓸 수 있다.&lt;/LI&gt;
&lt;LI&gt;페이스북은 리엑트를 라이브러리로 지원하기 때문에 RxJS를 포함하려고 하는 움직임은 없지만 커뮤니티에서 활발히 진행 중.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;또한 React와 함께 쓰는 Redux와 RxJS 는 궁합이 좋고 NetFilx에서 사용한 예가 있다.&lt;/LI&gt;
&lt;LI&gt;Angular가 RxJS를 플레임워크로 품은것은 관심가지고 볼 사항이다.&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;&lt;br /&gt;&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;</description>
      <category>JAVASCRIPT</category>
      <category>angular</category>
      <category>angularjs</category>
      <category>framework</category>
      <category>javascript</category>
      <category>library</category>
      <category>React</category>
      <category>ReactJS</category>
      <category>vanillajs</category>
      <category>VS</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/9</guid>
      <comments>https://bkim.tistory.com/9#entry9comment</comments>
      <pubDate>Mon, 22 May 2017 15:58:31 +0900</pubDate>
    </item>
    <item>
      <title>JavaScript Test Framework 비교 (Mocha vs Jasmine vs QUnit)</title>
      <link>https://bkim.tistory.com/8</link>
      <description>&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: rgb(238,238,238) 1px solid; BORDER-RIGHT: rgb(238,238,238) 1px solid; BORDER-BOTTOM: rgb(238,238,238) 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: rgb(238,238,238) 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: rgb(238,238,238)&quot;&gt;
&lt;P&gt;Node.js의 탄생과 JavaScript라는 언어의 범용성이 커짐에 따라 JavaScript의 테스트 환경은 점점 더 중요해졌다.&lt;/P&gt;
&lt;P&gt;JavaScript가 서버언어로 사용되면서 JavaScript 테스트는&amp;nbsp;e2e 테스트 뿐만아니라 BDD 또는 TDD가 가능한 유닛 테스트가 필요했고,&lt;/P&gt;
&lt;P&gt;기존&amp;nbsp;테스트 환경은 발전했고, 새로운&amp;nbsp;테스트 프레임워크들이 탄생했다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;여러종류의 테스트 프레임워크 중 Mocha, Jasmine, QUnit을 비교해보자.&lt;/P&gt;&lt;/DIV&gt;
&lt;H2&gt;&lt;SPAN style=&quot;FONT-SIZE: 14px&quot;&gt;결론&lt;/SPAN&gt;&lt;/H2&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-TOP: rgb(238,238,238) 1px solid; BORDER-RIGHT: rgb(238,238,238) 1px solid; BORDER-BOTTOM: rgb(238,238,238) 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: rgb(238,238,238) 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: rgb(238,238,238)&quot;&gt;
&lt;DIV&gt;&lt;SPAN style=&quot;FONT-SIZE: 14px&quot;&gt;테스트는 개발을 돕기위한 도구일 뿐 목적이 아님으로 개발 환경에 맞고 사용하기 편한 툴을 선택하면 된다.&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN style=&quot;FONT-SIZE: 14px&quot;&gt;테스트 속도 차이는 미비하고, 대부분의 툴들이 비동기 테스트를 지원함으로 테스트 툴간 성능비교는 무의미 한 것 같다.&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN style=&quot;FONT-SIZE: 14px&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN style=&quot;FONT-SIZE: 14px&quot;&gt;자바스크립트 프레임워크를 사용하지 않고 Jquery만 사용한다면 Qunit으로 간단하게 테스트 환경을 구축하면 되고&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN style=&quot;FONT-SIZE: 14px&quot;&gt;Angular와 같은 자바스크립트 프레임워크를 사용한다면 Mocha와 Jasmine중 선택하면 될 것이다.&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN style=&quot;FONT-SIZE: 14px&quot;&gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN style=&quot;FONT-SIZE: 14px&quot;&gt;TDD를 생각한다면 DOM 이 필요 없는 Jasmine을 확장성 높은 테스트 환경을 생각한다면 Mocha를 선택하면 좋겠다.&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN style=&quot;FONT-SIZE: 14px&quot;&gt;나는 테스트 기능에만 충실하고 별도의 Dependency 설정이 필요없어 사용하기 쉬운 Jasmine을 선택하고 싶다.&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;H2&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;테스트 비교&lt;/SPAN&gt;&lt;/H2&gt;
&lt;TABLE class=txc-table style=&quot;BORDER-TOP: medium none; FONT-FAMILY: ; BORDER-RIGHT: medium none; BORDER-COLLAPSE: collapse; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none&quot; cellSpacing=0 cellPadding=0 width=864 border=0 sans-serif;font-size:13px?=&quot;&quot; 고딕?,=&quot;&quot; 맑은=&quot;&quot;&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 168px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Mocha&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Jasmine&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 200px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Qunit&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 168px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;버전&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;3.4.0&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;2.6.1&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 200px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;2.3.2&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 168px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;인기&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;중간&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;높음&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 200px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;낮음&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 168px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;assertion 라이브러리&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;chai 라는 외부 라이브러리 사용&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;내장&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 200px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;내장&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 168px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;러너&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Karma 가능&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;Karma 가능&amp;nbsp;(Python, Ruby)&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 200px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;Karma 가능&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 168px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;난이도&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;보통&amp;nbsp;(3rd party library 필요, 유연함)&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;쉬움&amp;nbsp;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 200px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;가장 쉬움&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 35px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 168px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;커뮤니티&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 35px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;12.3K github&amp;nbsp;Stars, 4.45K stack over flow&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 35px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;12.4K github&amp;nbsp;Stars, 8.01K stack over flow&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 35px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 200px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;3.63K github&amp;nbsp;Stars, 1K stack over flow&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 168px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;특징&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;Simple, &lt;B&gt;&lt;SPAN style=&quot;COLOR: rgb(255,0,0)&quot;&gt;flexible&lt;/SPAN&gt;&lt;/B&gt;, fun javascript test framework for node.js &amp;amp; the browser&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 251px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;&lt;SPAN style=&quot;COLOR: rgb(255,0,0)&quot;&gt;&lt;B&gt;DOM-less&lt;/B&gt;&lt;/SPAN&gt; simple JavaScript testing framework&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 200px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;A JavaScript Unit Testing framewor&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;H2&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;테스트 문법&lt;/SPAN&gt;&lt;/H2&gt;
&lt;TABLE class=txc-table style=&quot;BORDER-TOP: medium none; FONT-FAMILY: ; BORDER-RIGHT: medium none; BORDER-COLLAPSE: collapse; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none&quot; cellSpacing=0 cellPadding=0 width=864 border=0 sans-serif;font-size:13px?=&quot;&quot; 고딕?,=&quot;&quot; 맑은=&quot;&quot;&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 442px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Mocha&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 199px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 442px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE style=&quot;FONT-SIZE: 9.8pt; FONT-FAMILY: 'Lucida Sans Typewriter'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;var &lt;/SPAN&gt;assert = require(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'assert'&lt;/SPAN&gt;)&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;describe&lt;/SPAN&gt;(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'Array'&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;, &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;function&lt;/SPAN&gt;() {&lt;br /&gt;  &lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;describe&lt;/SPAN&gt;(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'#indexOf()'&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;, &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;function&lt;/SPAN&gt;() {&lt;br /&gt;    &lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;it&lt;/SPAN&gt;(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;'should return -1 when the value is not present'&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;, &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;function&lt;/SPAN&gt;() {&lt;br /&gt;      assert.&lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;equal&lt;/SPAN&gt;(-&lt;SPAN style=&quot;COLOR: #6897bb&quot;&gt;1&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;, &lt;/SPAN&gt;[&lt;SPAN style=&quot;COLOR: #6897bb&quot;&gt;1&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;,&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6897bb&quot;&gt;2&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;,&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6897bb&quot;&gt;3&lt;/SPAN&gt;].&lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;indexOf&lt;/SPAN&gt;(&lt;SPAN style=&quot;COLOR: #6897bb&quot;&gt;4&lt;/SPAN&gt;))&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;    &lt;/SPAN&gt;})&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;  &lt;/SPAN&gt;})&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;})&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 31px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 442px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;Jasmine&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 28px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 442px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;&lt;PRE style=&quot;FONT-SIZE: 9.8pt; FONT-FAMILY: 'Lucida Sans Typewriter'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;&lt;P&gt;&lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;describe&lt;/SPAN&gt;(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;&quot;A suite is just a function&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;, &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;function&lt;/SPAN&gt;() {&lt;br /&gt;  &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;var &lt;/SPAN&gt;a&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;  &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;it&lt;/SPAN&gt;(&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;&quot;and so is a spec&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;, &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;function&lt;/SPAN&gt;() {&lt;br /&gt;    a = &lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;true&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;    &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;expect&lt;/SPAN&gt;(a).&lt;SPAN style=&quot;COLOR: #ffc66d&quot;&gt;toBe&lt;/SPAN&gt;(&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;true&lt;/SPAN&gt;)&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;  &lt;/SPAN&gt;})&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;})&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;/SPAN&gt;&lt;/P&gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 28px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 442px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;Qunit&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 327px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 442px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;&lt;PRE style=&quot;FONT-SIZE: 9.8pt; FONT-FAMILY: 'Lucida Sans Typewriter'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;&lt;P&gt;&lt;br /&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;!DOCTYPE &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;html&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;  &amp;lt;meta &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;charset=&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #a5c261&quot;&gt;&quot;utf-8&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;  &amp;lt;meta &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;name=&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #a5c261&quot;&gt;&quot;viewport&quot; &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;content=&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #a5c261&quot;&gt;&quot;width=device-width&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;  &amp;lt;title&amp;gt;&lt;/SPAN&gt;QUnit Example&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/title&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;  &amp;lt;link &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;rel=&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #a5c261&quot;&gt;&quot;stylesheet&quot; &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;href=&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #a5c261&quot;&gt;&quot;https://code.jquery.com/qunit/qunit-2.3.2.css&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;div &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;id=&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #a5c261&quot;&gt;&quot;qunit&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;div &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;id=&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #a5c261&quot;&gt;&quot;qunit-fixture&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;script &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;src=&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #a5c261&quot;&gt;&quot;https://code.jquery.com/qunit/qunit-2.3.2.js&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;script &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #bababa&quot;&gt;src=&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #a5c261&quot;&gt;&quot;tests.js&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #e8bf6a&quot;&gt;&amp;lt;/html&amp;gt;&lt;/SPAN&gt;&lt;br /&gt;&lt;/P&gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 28px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 442px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;&lt;PRE style=&quot;FONT-SIZE: 9.8pt; FONT-FAMILY: 'Lucida Sans Typewriter'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;&lt;br /&gt;QUnit.test( &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;&quot;hello test&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;, &lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-WEIGHT: bold; COLOR: #cc7832&quot;&gt;function&lt;/SPAN&gt;( assert ) {&lt;br /&gt;  assert.ok( &lt;SPAN style=&quot;COLOR: #6897bb&quot;&gt;1 &lt;/SPAN&gt;== &lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;&quot;1&quot;&lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;, &lt;/SPAN&gt;&lt;SPAN style=&quot;COLOR: #6a8759&quot;&gt;&quot;Passed!&quot; &lt;/SPAN&gt;)&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;br /&gt;&lt;/SPAN&gt;})&lt;SPAN style=&quot;COLOR: #cc7832&quot;&gt;;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;H2&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;사람들이 좋아하는 이유(출처&amp;nbsp;&lt;A class=tx-link href=&quot;https://stackshare.io/stackups/jasmine-vs-mocha-vs-qunit&quot; target=_blank&gt;https://stackshare.io/stackups/jasmine-vs-mocha-vs-qunit&lt;/A&gt;)&lt;/SPAN&gt;&lt;/H2&gt;
&lt;TABLE class=txc-table style=&quot;BORDER-TOP: medium none; FONT-FAMILY: ; BORDER-RIGHT: medium none; BORDER-COLLAPSE: collapse; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none&quot; cellSpacing=0 cellPadding=0 width=864 border=0 sans-serif;font-size:13px?=&quot;&quot; 고딕?,=&quot;&quot; 맑은=&quot;&quot;&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 287px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Mocha&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: rgb(204,204,204) 1px solid; HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 289px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Jasmine&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-TOP: #ccc 1px solid; HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;Qunit&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 287px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;105 오픈소스&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 289px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;50 TDD 로 사용할 수 있음&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;5 단순함&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 287px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;77 단순함&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 289px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;39 오픈소스&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;3 오픈소스&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 287px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;62 Promise 지원&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 289px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;14 RSpec 표준&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;3 세팅하기 쉬움&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 287px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;32 유연함&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 289px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;11 DOM조차 필요없는 독립성&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;2 Promise 지원&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 287px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;18 사용하기 쉬움&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 289px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;10 훌류한 커뮤니티&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 287px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;7 브라우저와 서버 테스트&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 289px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;5 세팅하기 쉬움&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 287px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;2 다른 좋은 대안이 없음&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 289px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;3 단숨함&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 287px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BORDER-LEFT: rgb(204,204,204) 1px solid&quot;&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: rgb(204,204,204) 1px solid; WIDTH: 289px; BORDER-BOTTOM: rgb(204,204,204) 1px solid&quot;&gt;
&lt;P&gt;&amp;nbsp;2 Pivotal-Labs에서 개발함&lt;/P&gt;&lt;/TD&gt;
&lt;TD style=&quot;HEIGHT: 24px; BORDER-RIGHT: #ccc 1px solid; WIDTH: 288px; BORDER-BOTTOM: #ccc 1px solid&quot;&gt;&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;H2&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;Stackshare 특징비교 (&lt;A class=tx-link href=&quot;https://stackshare.io/stackups/jasmine-vs-mocha-vs-qunit&quot; target=_blank&gt;https://stackshare.io/stackups/jasmine-vs-mocha-vs-qunit&lt;/A&gt;)&lt;/SPAN&gt;&lt;/H2&gt;
&lt;H2&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;구글 트렌드&lt;/SPAN&gt;&lt;/H2&gt;
&lt;DIV class=container style='BOX-SIZING: border-box; MAX-WIDTH: none; FONT-FAMILY: &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans; WIDTH: 1170px; COLOR: rgb(51,51,51); PADDING-LEFT: 15px; MARGIN-LEFT: auto; PADDING-RIGHT: 15px; MARGIN-RIGHT: auto'&gt;
&lt;DIV class=row style=&quot;BOX-SIZING: border-box; MARGIN-LEFT: -15px; MARGIN-RIGHT: -15px&quot;&gt;
&lt;DIV class=&quot;col-md-12 col-sm-12&quot; style=&quot;BOX-SIZING: border-box; POSITION: relative; FLOAT: left; PADDING-LEFT: 15px; MIN-HEIGHT: 1px; PADDING-RIGHT: 15px&quot;&gt;&lt;IFRAME style=&quot;BOX-SIZING: border-box; MAX-WIDTH: 1000px; BORDER-TOP: rgb(234,234,234) 1px solid; HEIGHT: 380px; BORDER-RIGHT: rgb(234,234,234) 1px solid; WIDTH: 900px; BORDER-BOTTOM: rgb(234,234,234) 1px solid; BORDER-LEFT: rgb(234,234,234) 1px solid; MARGIN: 0px auto 15px; DISPLAY: block&quot; src=&quot;https://www.google.com/trends/fetchComponent?q=Jasmine,Mocha,QUnit&amp;amp;cid=TIMESERIES_GRAPH_0&amp;amp;export=5&amp;amp;w=900&amp;amp;h=380&quot; frameBorder=0&gt;&lt;/IFRAME&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;
&lt;H2&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/H2&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;br /&gt;&lt;/DIV&gt;
&lt;DIV id=stackups-container class=container style='BOX-SIZING: border-box; MAX-WIDTH: none; FONT-FAMILY: &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans; COLOR: rgb(51,51,51); PADDING-LEFT: 15px; MARGIN-LEFT: auto; PADDING-RIGHT: 15px; MARGIN-RIGHT: auto'&gt;&lt;BR style=&quot;BOX-SIZING: border-box&quot;&gt;&lt;/DIV&gt;
&lt;DIV class=container style='BOX-SIZING: border-box; MAX-WIDTH: none; FONT-FAMILY: &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans; WIDTH: 1170px; COLOR: rgb(51,51,51); PADDING-LEFT: 15px; MARGIN-LEFT: auto; PADDING-RIGHT: 15px; MARGIN-RIGHT: auto'&gt;
&lt;DIV class=&quot;sp-section-titles sp-description-section-title&quot; style=&quot;BOX-SIZING: border-box; FONT-SIZE: 13pt; TEXT-TRANSFORM: uppercase; COLOR: grey; MARGIN: 25px 0px 5px&quot;&gt;&lt;br /&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;br /&gt;&lt;/P&gt;</description>
      <category>JAVASCRIPT</category>
      <category>Jasmine</category>
      <category>javascript test</category>
      <category>javascript test framework</category>
      <category>mocha</category>
      <category>QUnit</category>
      <category>자바스크립트 테스트</category>
      <category>자바스크립트 테스트 프레임워크</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/8</guid>
      <comments>https://bkim.tistory.com/8#entry8comment</comments>
      <pubDate>Wed, 17 May 2017 16:44:18 +0900</pubDate>
    </item>
    <item>
      <title>IntelliJ 에서 Angular 2 프로젝트 시작하기</title>
      <link>https://bkim.tistory.com/7</link>
      <description>&lt;div class=&quot;txc-textbox&quot; style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;p&gt;Angular를 시작하기 위해 문서를 찾아보면 대부분 편집 툴로 Visual Studio Code 를 추천한다.&lt;/p&gt;
&lt;p&gt;처음 접해보는 용어와 Node라는 런타임, 그리고 npm 사이에서 새로운 편집툴은 Angular의 진입 장벽을 더욱 높인다.&lt;/p&gt;
&lt;p&gt;평소 사용하고 있는 IDE인 IntelliJ에서 Angular2(이하 Angular) 프로젝트를 생성할 수 있으면 조금이나마 진입 장벽을 낮출 수 있을것 같아서 내용을 정리한다.&lt;/p&gt;
&lt;p&gt;해당 문서는 Window 환경을 기준으로 작성했다.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;FONT-SIZE: 11pt&quot;&gt;1. N&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style=&quot;FONT-SIZE: 11pt&quot;&gt;ode.js&amp;nbsp;설치&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;https://nodejs.org/ko/ 에 접속하여 stable 버전인 v6.10.3 LTS 를 다운받고 설치한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;p&gt;Node.js라는 개념이 쉽게 와닿지 않는다.&amp;nbsp; 노드란 무엇일까?&lt;/p&gt;
&lt;p&gt;&quot;Node.js 는 Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임&quot; 이라고 공식페이지에서 말한다.&lt;/p&gt;
&lt;p&gt;런타임이란 프로그램이 실행되고 있을 때 존재하는 곳을 뜻하는데, 우리가 익숙하게 사용하고 있는 JRE를 떠올리면 쉽다.&lt;/p&gt;
&lt;p&gt;JRE는 Java Runtime Environment의 준말로 우리가 개발한 JAVA 어플리케이션을 구동하기 위한 환경인 것이다.&lt;/p&gt;
&lt;p&gt;이처럼 노드는 JavaScript로 개발된 어플리케이션을 구동하기 위한 환경이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;또한 Node.js의 패키지 생태계를 지원하기 위해 npm 이란 것이 있다.&lt;/p&gt;
&lt;p&gt;리눅스에서 흔히 사용하는 yum, apt-get, rpm과 비슷한 개념의 패키지 매니져이며 npm은 JavaScript를 위한 패키지 매니저라고 보면 된다.&lt;/p&gt;
&lt;p&gt;Node.js를 설치할때 npm도 같이 설치 된다.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;FONT-SIZE: 11pt&quot;&gt;2. Angular CLI 설치 (https://cli.angular.io/)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;cmd 창에서&amp;nbsp;&lt;/p&gt;
&lt;p&gt;npm install -g @angular/cli@latest&amp;nbsp;&lt;/p&gt;
&lt;p&gt;npm install --save-dev @angular/cli@latest&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기까지 설치 후 cmd 창에서 ng -v를 날려보면 다음과 같은 버전 정보가 나와야한다.&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 508px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/246D8834591BBDF21E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F246D8834591BBDF21E&quot; width=&quot;508&quot; height=&quot;209&quot; filename=&quot;1.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;COLOR: #ff0000&quot;&gt;#최근 angular 패키지의 이름이 변경되었고, 이전버전을 디프리케이트 했다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;COLOR: #ff0000&quot;&gt;골뱅이가 붙어서 시작하는게&amp;nbsp;변경된 버전이니&amp;nbsp;책이나 구버전 문서들을 볼때 주의해야겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;BORDER-TOP: #eeeeee 1px solid; BORDER-RIGHT: #eeeeee 1px solid; BORDER-BOTTOM: #eeeeee 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: #eeeeee 1px solid; PADDING-RIGHT: 10px; BACKGROUND-COLOR: #eeeeee&quot;&gt;
&lt;p&gt;Angular&amp;nbsp;프로젝트 생성, 빌드, 테스트를 도와주는 command line interface(CLI)이다.&lt;/p&gt;
&lt;p&gt;Angular CLI 로 프로젝트를 생성하면 각각 따로 설정해줘야하는 polyFill, tsConfig, typings, karma 등등 각종 의존성등을 설정해준다.&lt;/p&gt;
&lt;p&gt;NodeJs를 처음 접하면 온갖 의존성 관리에 좌절하기 마련인데, 이러한 문제를&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Angular CLI는 가장 최적화된 상태로 프로젝트를 생성함으로써&amp;nbsp;진입 문턱을 낮춰준다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이밖에 쉽게 테스트할 수 있는 로컬 서버과 테스트까지 제공해주니 각각 따로 세팅하는것 보다 Angular CLI 사용하는것을 추천한다.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;FONT-SIZE: 11pt&quot;&gt;3. IntelliJ 플러그인 설치&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;IntelliJ에는 Angular 프레임워크가 없다.&amp;nbsp;(Web Storm 에는 있음)&lt;/p&gt;
&lt;p&gt;플러그인으로 설치 하기 위해 IntelliJ Settings -&amp;gt; Plugins -&amp;gt; Browse Repositories -&amp;gt; AngularJS 를 검색 설치한다.&lt;/p&gt;
&lt;p&gt;재시작 후 File -&amp;gt; New -&amp;gt; Project -&amp;gt; Static Web 을 보면 Angular CLI 를 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;FONT-SIZE: 11pt&quot;&gt;4. 프로젝트 생성&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;File -&amp;gt; New -&amp;gt; Project -&amp;gt; Static Web 을 보면 Angular CLI 후 Next를 클릭하면,&lt;/p&gt;
&lt;p&gt;프로젝트 이름과 위치를 지정할 수 있으며, Node Interpreter 와 Angular CLI를 선택 할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Node 는 1번 단계에서 설치한 node.exe.의 위치를, Angular CLI 는 npm으로 설치한 Angular CLI 패키지 위치를 지정해주면된다.&lt;/p&gt;
&lt;p&gt;프로젝트 생성을 마치면 IntelliJ가 자동으로 Angular CLI에 new 명령어를 날려 필요한 라이브러리들을 다운받고 설치한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/27129A35591BBF3A13&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F27129A35591BBF3A13&quot; width=&quot;900&quot; height=&quot;355&quot; filename=&quot;2.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 838px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/222FF93C591BC0211A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F222FF93C591BC0211A&quot; width=&quot;838&quot; height=&quot;1094&quot; filename=&quot;3.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Angular CLI 위치가 목록에 보이지 않는다면 다음 사이트를 참조해보자.&lt;/p&gt;
&lt;p&gt;https://www.jetbrains.com/help/idea/2017.1/using-angular.html&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://revf.tistory.com/entry/IntelliJ%EC%97%90%EC%84%9C-Angular2-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-with-Angular-CLI&quot;&gt;http://revf.tistory.com/entry/IntelliJ%EC%97%90%EC%84%9C-Angular2-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-with-Angular-CLI&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;FONT-SIZE: 11pt&quot;&gt;5. output 세팅&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;AngularJs는 타입스크립트를 사용하기 때문에 타입스크립트를 자바스크립트로 컴파일 하는 빌드과정이 필요하다.&lt;/p&gt;
&lt;p&gt;IntelliJ 터미널 또는 좌측 하단 npm 창에서 build 를 클릭하면 명시적으로 컴파일할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이때 컴파일 결과물들을 임의의 위치에 저장하려면&amp;nbsp; angular-cli.json 설정을 수정하면 된다.&lt;/p&gt;
&lt;p&gt;추후 스프링과 연동할때 필요할것으로 보이므로 관심이 있으면 수정해보자.&lt;/p&gt;&lt;pre style=&quot;FONT-SIZE: 9.8pt; FONT-FAMILY: 'Lucida Sans Typewriter'; COLOR: #a9b7c6; BACKGROUND-COLOR: #2b2b2b&quot;&gt;&lt;span style=&quot;COLOR: #9876aa&quot;&gt;&quot;outDir&quot;&lt;/span&gt;&lt;span style=&quot;COLOR: #cc7832&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;COLOR: #6a8759&quot;&gt;&quot;dist&quot;&lt;/span&gt;&lt;span style=&quot;COLOR: #cc7832&quot;&gt;,  --&amp;gt; &lt;span style=&quot;COLOR: #9876aa&quot;&gt;&quot;outDir&quot;&lt;/span&gt;&lt;span style=&quot;COLOR: #cc7832&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;COLOR: #6a8759&quot;&gt;&quot;output&quot;&lt;/span&gt;&lt;span style=&quot;COLOR: #cc7832&quot;&gt;,  &lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/256E8C3B591BC0D71C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F256E8C3B591BC0D71C&quot; width=&quot;900&quot; height=&quot;391&quot; filename=&quot;4.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;빌드 시작&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 431px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/22657338591BC1602F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F22657338591BC1602F&quot; width=&quot;431&quot; height=&quot;423&quot; filename=&quot;5.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;빌드 성공&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 687px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/24131438591BC16019&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F24131438591BC16019&quot; width=&quot;687&quot; height=&quot;181&quot; filename=&quot;6.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;빌드 결과물&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 430px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/275A0138591BC1612A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F275A0138591BC1612A&quot; width=&quot;430&quot; height=&quot;395&quot; filename=&quot;7.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;FONT-SIZE: 11pt&quot;&gt;6. 프로젝트 실행&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;생성한 프로젝트를 실행하기 위해 Angular CLI 는 serve 명령어를 지원해준다.&lt;/p&gt;
&lt;p&gt;IntellJ의 npm 창에는 start로 표시되어있는데, 클릭해보면 터미널 창에서 ng serve 명령어를 날리는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;ng serve 를 하면 콘솔창에서 연결정보 (localhost:4200)를 확인 할 수있다.&lt;/p&gt;
&lt;p&gt;(ng serve 는 ng build 를 포함한다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 729px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/232C7835591BC49E34&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F232C7835591BC49E34&quot; width=&quot;729&quot; height=&quot;436&quot; filename=&quot;8.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;FONT-SIZE: 11pt&quot;&gt;7. 실행 확인&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;별다른 설정을 하지 않았다면, ng serve로 시작한 어플리케이션은 라이브 코딩을 지원한다. (자동 빌드)&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 438px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/23083938591BC6C73C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F23083938591BC6C73C&quot; width=&quot;438&quot; height=&quot;280&quot; filename=&quot;9.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;src/app/app.component.ts 의 title 변수를 변경하고 저장하면 자동으로 업데이트 되는것을 확인 할 수 있다.&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;FLOAT: none; TEXT-ALIGN: left; CLEAR: none&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/26739F38591BC6C830&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F26739F38591BC6C830&quot; width=&quot;900&quot; height=&quot;446&quot; filename=&quot;10.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>ANGULAR</category>
      <category>angular</category>
      <category>angular 2 시작하기</category>
      <category>angular cli</category>
      <category>angularjs2</category>
      <category>IntelliJ</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/7</guid>
      <comments>https://bkim.tistory.com/7#entry7comment</comments>
      <pubDate>Tue, 16 May 2017 18:19:33 +0900</pubDate>
    </item>
    <item>
      <title>Linux 환경에서 Selenium으로 웹 테스트 자동화하기 (Spring, CentOS, Jenkins)</title>
      <link>https://bkim.tistory.com/6</link>
      <description>&lt;h2&gt;&lt;span style=&quot;background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);&quot;&gt;목적&lt;/span&gt;&lt;/h2&gt;&lt;hr&gt;&lt;p&gt;&lt;span style=&quot;background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;윈도우 로컬환경에서 셀레늄 테스트 모듈을 구현하는 것은 비교적 쉽게 구현할 수 있다.&lt;/p&gt;&lt;p&gt;문제는 커맨드 환경인 리눅스 서버에서 가상 모니터를 띄우고 젠킨스와 연동하여 테스트를 자동화 하는것이다.&lt;/p&gt;&lt;p&gt;때문에 CentOS 환경에서 셀레늄 테스트를 자동화 하는데&amp;nbsp;초점을 맞추어 가이드를 썼다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;해당 포스트는 아래 내용을 포함한다.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;Selenium을 이용하여 웹 테스트 모듈을 구현.&lt;/li&gt;&lt;li&gt;CentOS와&amp;nbsp;Jenkins를 이용하여 셀레늄 웹 테스트를 자동화.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;&lt;span style=&quot;background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);&quot;&gt;테스트 환경&lt;/span&gt;&lt;/h2&gt;&lt;hr&gt;&lt;p&gt;&lt;span style=&quot;background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;최대한 최신환경을 사용하려 노력했다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;셀레늄 : 3.2.0 (selenium-java, selenium-chrome-driver, selenium-server)&lt;/p&gt;&lt;p&gt;브라우저 :&amp;nbsp;Chrome&amp;nbsp;56.0.2924.87 (64-bit)&lt;/p&gt;&lt;p&gt;크롬 드라이버 :&amp;nbsp;&lt;a href=&quot;https://sites.google.com/a/chromium.org/chromedriver/downloads&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;ChromeDriver 2.27&lt;/a&gt;&lt;/p&gt;&lt;p&gt;스프링 : 3.2.17.RELEASE&lt;/p&gt;&lt;p&gt;CentOS :&amp;nbsp;CentOS Linux release 7.1.1503 (Core)&lt;/p&gt;&lt;p&gt;Jdk&amp;nbsp;: 1.8.0_101 (Oracle)&lt;/p&gt;&lt;h2&gt;&lt;span style=&quot;background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);&quot;&gt;테스트 구현&lt;/span&gt;&lt;/h2&gt;&lt;hr&gt;&lt;p&gt;&lt;span style=&quot;background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;1.Spring&amp;nbsp;Maven 프로젝트를 생성하여, 테스트환경을 구성한다.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;2.셀레늄 테스트를 위하여 pom.xml에 라이브러리 의존성을 설정한다.&lt;/b&gt;&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Lucida Sans Typewriter';font-size:9.8pt;&quot;&gt;&lt;p&gt;&lt;span style=&quot;color:#808080;&quot;&gt;&amp;lt;!-- pom.xml selenium --&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;org.seleniumhq.selenium&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;selenium-java&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;3.2.0&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;org.seleniumhq.selenium&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;selenium-chrome-driver&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;3.2.0&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;org.seleniumhq.selenium&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;selenium-server&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;3.2.0&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#e8bf6a;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;3.테스트를 작성한다.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&amp;nbsp; setUp() 에서 크롬 드라이버 위치 지정&lt;/p&gt;&lt;p&gt;&amp;nbsp; 테스트 내용은 구글에서 &quot;어쩌다, 블로그&quot;를 검색&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp; -&amp;gt; 검색 결과중 &amp;nbsp;&quot;어쩌다, 블로그&quot;라는 문자열을 가진 링크를 10초간 대기하면 찾기&lt;/p&gt;&lt;p&gt;&amp;nbsp; -&amp;gt; 클릭&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Lucida Sans Typewriter';font-size:9.8pt;&quot;&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public class &lt;/span&gt;SeleniumSampleTest {&lt;br /&gt;&lt;br /&gt;   &lt;span style=&quot;color:#cc7832;&quot;&gt;private &lt;/span&gt;WebDriver &lt;span style=&quot;color:#9876aa;&quot;&gt;driver&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;@After&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public void &lt;/span&gt;&lt;span style=&quot;color:#ffc66d;&quot;&gt;tearDown&lt;/span&gt;() &lt;span style=&quot;color:#cc7832;&quot;&gt;throws &lt;/span&gt;Exception {&lt;br /&gt;&lt;br /&gt;      Thread.&lt;span style=&quot;font-style:italic;&quot;&gt;sleep&lt;/span&gt;(&lt;span style=&quot;color:#6897bb;&quot;&gt;5000&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;driver&lt;/span&gt;.quit()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;   &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;   &lt;span style=&quot;color:#bbb529;&quot;&gt;@Before&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public void &lt;/span&gt;&lt;span style=&quot;color:#ffc66d;&quot;&gt;setUp&lt;/span&gt;() &lt;span style=&quot;color:#cc7832;&quot;&gt;throws &lt;/span&gt;Exception {&lt;br /&gt;&lt;br /&gt;      System.&lt;span style=&quot;font-style:italic;&quot;&gt;setProperty&lt;/span&gt;(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;webdriver.chrome.driver&quot;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;D:&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#6a8759;&quot;&gt;gecko&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#6a8759;&quot;&gt;chromedriver.exe&quot;&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;driver &lt;/span&gt;= &lt;span style=&quot;color:#cc7832;&quot;&gt;new &lt;/span&gt;ChromeDriver()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;   &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;   &lt;span style=&quot;color:#bbb529;&quot;&gt;@Test&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#bbb529;&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;public void &lt;/span&gt;&lt;span style=&quot;color:#ffc66d;&quot;&gt;testGetGoogle&lt;/span&gt;() &lt;span style=&quot;color:#cc7832;&quot;&gt;throws &lt;/span&gt;Exception {&lt;br /&gt;&lt;br /&gt;      &lt;span style=&quot;color:#9876aa;&quot;&gt;driver&lt;/span&gt;.get(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;http://www.google.com&quot;&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;      &lt;/span&gt;WebElement searchBar = &lt;span style=&quot;color:#9876aa;&quot;&gt;driver&lt;/span&gt;.findElement(By.&lt;span style=&quot;font-style:italic;&quot;&gt;cssSelector&lt;/span&gt;(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;#lst-ib&quot;&lt;/span&gt;))&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;      &lt;/span&gt;searchBar.sendKeys(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#6a8759;font-family:'굴림체';&quot;&gt;어쩌다&lt;/span&gt;&lt;span style=&quot;color:#6a8759;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6a8759;font-family:'굴림체';&quot;&gt;블로그&lt;/span&gt;&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;&lt;/span&gt;)&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color:#9876aa;&quot;&gt;driver&lt;/span&gt;.findElement(By.&lt;span style=&quot;font-style:italic;&quot;&gt;cssSelector&lt;/span&gt;(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;#_fZl&quot;&lt;/span&gt;)).click()&lt;span style=&quot;color:#cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;      &lt;/span&gt;WebElement bkim = &lt;span style=&quot;color:#cc7832;&quot;&gt;new &lt;/span&gt;WebDriverWait(&lt;span style=&quot;color:#9876aa;&quot;&gt;driver&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6897bb;&quot;&gt;10&lt;/span&gt;).until(ExpectedConditions.&lt;span style=&quot;font-style:italic;&quot;&gt;elementToBeClickable&lt;/span&gt;(
&lt;span style=&quot;font-style:italic;&quot;&gt;                                                                                   linkText&lt;/span&gt;(&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#6a8759;font-family:'굴림체';&quot;&gt;어쩌다&lt;/span&gt;&lt;span style=&quot;color:#6a8759;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6a8759;font-family:'굴림체';&quot;&gt;블로그&lt;/span&gt;&lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;&lt;/span&gt;)))&lt;span style=&quot;color:#cc7832;&quot;&gt;;
      &lt;/span&gt;bkim.click()&lt;span style=&quot;font-size: 9.8pt; color: rgb(204, 120, 50);&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#cc7832;&quot;&gt;   &lt;/span&gt;}
}&lt;/pre&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;4.테스트 정상작동확인.&lt;/b&gt;&lt;/p&gt;&lt;h2&gt;리눅스에서 셀레늄 환경 구성&amp;nbsp;하기&lt;/h2&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;CentOS 메이븐과 젠킨스가 설치되어 있다는 가정하에 진행한다.&lt;/p&gt;&lt;p&gt;젠킨스가 아니더라도 메이븐 테스트를 진행하는 방법은 많다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;아래 가이드하는 환경 설정 후 메이븐 테스트를 위해 다른 툴을 사용하여도 무방하다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;1. 혹시 GCC가 깔려있지 않으면 설치해주자. 크롬 실행 시 필요한 라이브러리들을 가지고있다.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;2. 크롬 설치 (https://tecadmin.net/install-google-chrome-in-centos-rhel-and-fedora/)&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위 링크에서 크롬을 설치하여도 GUI 환경이 준비되지 않은채 google-chrome 명령어를 날리면&lt;/p&gt;&lt;p&gt;browser_main_loop.cc(272)] Gtk: cannot open display 와 같은 에러를 뱉으며 크롬이 실행 되지 않는다. 우선 설치만 해두자.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;3. 크롬 드라이버 다운로드 (https://chromedriver.storage.googleapis.com/index.html?path=2.27/)&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위 링크에서 환경에 맞는 드라이버를 다운로드 후 적절한 경로에 다운 받은 후,&lt;/p&gt;&lt;p&gt;테스트&amp;nbsp;소스에서 chrome.driver 경로를 맞춰주자.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;4. Xwindows 설치 (http://chandrewz.github.io/blog/selenium-on-centos)&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위 링크를 참고하거나 아래 명령어를 수행한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;설치&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Lucida Sans Typewriter';font-size:9.8pt;&quot;&gt;&lt;p&gt;$ sudo yum install Xvfb libXfont Xorg &lt;br /&gt;$ sudo yum groupinstall &lt;span style=&quot;color:#6a8759;&quot;&gt;&quot;X Window System&quot; &quot;Desktop&quot; &quot;Fonts&quot; &quot;General Purpose Desktop&quot;&lt;/span&gt;&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;99번 포트로 Xwindows 실행&amp;nbsp;&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Lucida Sans Typewriter';font-size:9.8pt;&quot;&gt;&lt;p&gt;$ Xvfb :&lt;span style=&quot;color:#6897bb;&quot;&gt;99 &lt;/span&gt;-ac -screen &lt;span style=&quot;color:#6897bb;&quot;&gt;0 1280&lt;/span&gt;x1024x24 &amp;amp;&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;99번 포트로 XWindows display 포트 지정&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Lucida Sans Typewriter';font-size:9.8pt;&quot;&gt;$ export DISPLAY=:&lt;span style=&quot;color:#6897bb;&quot;&gt;99&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;이제 다시 google-chrome 명령어로 크롬을 실행해보면 cannot open display &amp;nbsp;와같은 에러가 사라진것을 알 수 있다.&lt;/p&gt;&lt;h2&gt;&lt;span style=&quot;background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);&quot;&gt;젠킨스 연동&lt;/span&gt;&lt;/h2&gt;&lt;hr&gt;&lt;p&gt;&lt;span style=&quot;background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;1. 테스트로 만든 maven 프로젝트를 서버로 업로드한다.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp;(메이븐으로 테스트를 돌릴것이기 때문에 따로 빌드하여 올릴 필요는 없다.)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;2. Jenkins에서&amp;nbsp;Freestyle project를 하나 생성한다.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;3. 프로젝트 이름과 로그 로테이션을 각각 설정한다.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;4. 빌드 환경에서 테스트 전후로 Xwindow를 사용할 수 있도록 Start Xvfb before the build, and shut it down after. 를 반드시 체크한다.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/233B6D3358BE595B36&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F233B6D3358BE595B36&quot; width=&quot;900&quot; height=&quot;91&quot; filename=&quot;1.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;5. Build 단계로 이동하여 Execute shell 항목에 테스트를&amp;nbsp;실행할 쉘 명령어를 입력한다.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; 2번단계에서 소스 업로드한 폴더로 이동 (cd /home1/irteam/deploy/test)&lt;/p&gt;&lt;p&gt;&amp;nbsp; 메이븐으로 테스트 실행 &amp;nbsp;-Dtest=클래스명#메소드명 test &amp;nbsp;(mvn -Dtest=SeleniumSampleTest#testGetGoogle test)&lt;/p&gt;&lt;pre style=&quot;background-color:#2b2b2b;color:#a9b7c6;font-family:'Lucida Sans Typewriter';font-size:9.8pt;&quot;&gt;&lt;p&gt;cd /home1/irteam/deploy/test&lt;br /&gt;mvn -Dtest=SeleniumSampleTest#&lt;span style=&quot;background-color: rgb(52, 65, 52); font-size: 9.8pt;&quot;&gt;testGetGoogle &lt;/span&gt;&lt;span style=&quot;font-size: 9.8pt;&quot;&gt;test&lt;/span&gt;&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;6. 테스트 수행 및 테스트 성공 확인.&lt;/b&gt;&lt;/p&gt;&lt;h2&gt;마치며&lt;/h2&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;셀레늄은 브라우저를 포함한 사용자 환경을 그대로 재현하여 테스트하기 때문에, 클라이언트에 가장 가까운 테스트 툴이라 할 수 있다.&lt;br /&gt;그 특성때문에 리눅스 서버에서 수행하기에는 어려움이 따른다. 이를 해결하고자 삽질했던 내용들을&amp;nbsp;블로그에 남겼다.&lt;/p&gt;&lt;p&gt;리눅스에서 셀레늄을 돌리고자하는 분들의 삽질에 도움이 되길바란다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;☞ 관련하여 어떤 내용이듯 댓글로 달아주시면 답글 드리겠습니다. 감사합니다.&lt;/p&gt;</description>
      <category>WEB</category>
      <category>CentOS</category>
      <category>Linux</category>
      <category>selenium</category>
      <category>셀레늄</category>
      <category>셀레늄 테스트</category>
      <category>웹 테스트 자동화</category>
      <category>크롬</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/6</guid>
      <comments>https://bkim.tistory.com/6#entry6comment</comments>
      <pubDate>Tue, 7 Mar 2017 14:52:31 +0900</pubDate>
    </item>
    <item>
      <title>AWS CodeBuild 사용하여 빌드하기</title>
      <link>https://bkim.tistory.com/5</link>
      <description>&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin-top: 2em; margin-right: 0px; margin-bottom: 0.5em; border-bottom: 1px solid rgb(145, 150, 153); font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;목적&lt;/span&gt;&lt;/h2&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;그동안 프로젝트 CI(Continuous Integration) 관리를 위하여&amp;nbsp;빌드서버를 따로 관리해야하는 번거로움이 있었는데,&amp;nbsp;&lt;/div&gt;&lt;div&gt;AWS에서 이러한 어려움을 덜어주기위해 AWS CodeBuild를 출시했다.&lt;/div&gt;&lt;div&gt;보편적으로 사용되고 있는 빌드툴인 젠킨스를 사용하기 위해서는 다소 복잡한 세팅과정과 빌드용&amp;nbsp;서버가 필요했다.&lt;/div&gt;&lt;div&gt;빌드를 위한 작업자와 서버에 들어가는 비용을 줄이기&amp;nbsp;위하여, AWS CodeBuild를 사용하려 한다.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;빌드하고자하는 프로젝트의 환경은 Maven, Spring4, Github 이다.&lt;/div&gt;&lt;div&gt;&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin-top: 2em; margin-right: 0px; margin-bottom: 0.5em; border-bottom: 1px solid rgb(145, 150, 153); text-align: left; clear: none; float: none;&quot;&gt;AWS CodeBuild란?&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 100px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/25191C43585017582C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F25191C43585017582C&quot; width=&quot;100&quot; height=&quot;100&quot; filename=&quot;Developer Tools_AWSCodeBuild.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;CodeBuild는 빌드에 소요되는 시간(분당 $0.005)에 과금하며, 빌드용 서버 사양을 선택할 수 있다.&lt;/div&gt;&lt;div&gt;테스트 해본결과 보통 5분이면 빌드가 완료되었고, 가격으로 따지면 빌드당 $0.025이다. 왠만큼 큰 프로젝트가 아니면 저렴하게 사용할 수 있겠다.&lt;/div&gt;&lt;div&gt;소스 레파지토리는 AWS CodeCommit, GitHub, S3bucket를 사용할 수 있고 언어 대부분의 서버언어를 커버한다.&lt;/div&gt;&lt;div&gt;빌드 스펙은 YAML 양식을 사용하는데 상세 내용은 아래 세팅하기에서 다루겠다.&lt;/div&gt;&lt;div&gt;상세 스펙은 한글로 번역된 페이지를 첨부하여 대신한다.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/korea/aws-codebuild-fully-managed-build-service/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://aws.amazon.com/ko/blogs/korea/aws-codebuild-fully-managed-build-service/&lt;/a&gt;&lt;/div&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: rgb(51, 51, 51); font-family: HelveticaNeue, Helvetica, Helvetica, Arial, sans-serif; font-size: 14px;&quot;&gt;&amp;nbsp;빌드 서버를 설치, 설정 및 확장 및 패치 등에 신경쓰지 않고,&amp;nbsp;&lt;/span&gt;&lt;span title=&quot;&quot; style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: HelveticaNeue, Helvetica, Helvetica, Arial, sans-serif; font-size: 14px;&quot;&gt;CodeBuild&lt;/span&gt;&lt;span style=&quot;color: rgb(51, 51, 51); font-family: HelveticaNeue, Helvetica, Helvetica, Arial, sans-serif; font-size: 14px;&quot;&gt;를 활용하여 개발 과정에서 유연상을 보장하고 여러 형태의 빌드 상태나 호환성의 불일치 문제를 해결할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;span title=&quot;&quot; style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: HelveticaNeue, Helvetica, Helvetica, Arial, sans-serif; font-size: 14px;&quot;&gt;CodeBuild&lt;/span&gt;&lt;span style=&quot;color: rgb(51, 51, 51); font-family: HelveticaNeue, Helvetica, Helvetica, Arial, sans-serif; font-size: 14px;&quot;&gt;를 사용 하면, 사전에 빌드 서버를 프로비저닝 할 필요가 없으며, 대기중인 빌드를 쌓아 두는 대신에 빌드 볼륨을 활용할 수 있도록 자동으로 확장됩니다. 분당 $0.005부터 시작하는 가격으로 분당 기준으로 빌드 리소스에 비용을 지불하기 때문에 사용한 시간만 비용을 지불합니다.&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin-top: 2em; margin-right: 0px; margin-bottom: 0.5em; border-bottom: 1px solid rgb(145, 150, 153);&quot;&gt;세팅하기&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;빌드를 위한 서버세팅이 필요 없었기 때문에, 전체적인 빌드 세팅은 젠킨스보다 훨씬 간편했다.&amp;nbsp;&lt;/div&gt;&lt;div&gt;다만, 레퍼런스가 적고 ASIA쪽 리전은 서비스 이전이라 Oregon 리전을 사용해야하는 번거로움이 있었다.&lt;/div&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;CodeBuild 프로젝트 생성 (Configure your Project)&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;CodeBuild 서비스에서 Create Project를 클릭한다.&lt;/li&gt;&lt;li&gt;Project name은 아무거나 상관없다.&amp;nbsp;&lt;/li&gt;&lt;li style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 888px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/265CD939584E6BE634&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F265CD939584E6BE634&quot; width=&quot;888&quot; height=&quot;199&quot; filename=&quot;1.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Source: What to build&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;소스코는 github에서 가져오려고한다. 간단하게 사용자 인증을 하면, 내 깃헙의 레파지토리를 볼 수 있다.&lt;/li&gt;&lt;li style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 884px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2167743A584E6C482E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2167743A584E6C482E&quot; width=&quot;884&quot; height=&quot;176&quot; filename=&quot;2.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;buildspec.yml 작성&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;프로젝트 루트레벨에 buildspec.yml 이름의 파일을 생성한다.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;실직적으로 빌드를 위한&amp;nbsp;스크립트내용을 담고 있는 파일이다.&lt;br /&gt;&lt;br /&gt;version : 0.1 (빌드할 프로젝트의 버전)&lt;br /&gt;environment_variables&amp;nbsp;: (환경 변수로 빌드 시 입력받을 수도 있지만 여기서도 받을 수 있다. 없어도 됨)&lt;br /&gt;phases : 빌드 단계별 설정으로 pre bulid 와 build만 작성했다.&lt;br /&gt;artifacts : 빌드 완료 후 결과물 경로를 위한 설정으로 AWS S3에 업로드하기 위한 필수조건이다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 728px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/225F8835584E6D6E35&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F225F8835584E6D6E35&quot; width=&quot;728&quot; height=&quot;333&quot; filename=&quot;3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Environment: How to build&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;빌드 스크립트를 buildspec.yml를 통해 정의했다면 빌드 환경만 선택해 주면 된다.&lt;/li&gt;&lt;li&gt;OS는 현재 Ubuntu만 사용가능하다. (Java, jdk8 선택)&lt;br /&gt;&lt;/li&gt;&lt;li style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 885px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/261CC534584E6F4401&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F261CC534584E6F4401&quot; width=&quot;885&quot; height=&quot;405&quot; filename=&quot;4.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Artifacts: Where to put the artifacts from this build project&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li style=&quot;text-align: left; clear: none; float: none;&quot;&gt;빌드 후 생성되는 war 파일을 저장할 곳을 지정한다.&lt;/li&gt;&lt;li style=&quot;text-align: left; clear: none; float: none;&quot;&gt;같은 리전의 S3 저장소만 사용할 수 있음에 유의한다.&lt;br /&gt;&lt;/li&gt;&lt;li style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 884px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/262EE13B584E702D25&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F262EE13B584E702D25&quot; width=&quot;884&quot; height=&quot;231&quot; filename=&quot;4.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Service role &amp;amp; Advanced settings&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li style=&quot;text-align: left; clear: none; float: none;&quot;&gt;서비스 롤과 빌드 서버 성능, 환경변수값을 지정할 수 있다.&lt;/li&gt;&lt;li style=&quot;text-align: left; clear: none; float: none;&quot;&gt;자세한 설명은 생략한다.&lt;br /&gt;&lt;/li&gt;&lt;li style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 894px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/257B4A3C584E70B82C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F257B4A3C584E70B82C&quot; width=&quot;894&quot; height=&quot;948&quot; filename=&quot;5.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin-top: 2em; margin-right: 0px; margin-bottom: 0.5em; border-bottom: 1px solid rgb(145, 150, 153);&quot;&gt;빌드하기&lt;/h2&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;이제 &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;Source Version&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;에 빌드할 브랜치명만 추가하면 프로젝트를 빌드할 수 있다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;빌드 과정과 로그가 친절하게 표시된다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/224B843A584E719C17&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F224B843A584E719C17&quot; width=&quot;900&quot; height=&quot;449&quot; filename=&quot;6.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;빌드과 완료되면 단계별 결과와 로그를 확인 할 수 &lt;/span&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;있다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/211B7537584E72081A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F211B7537584E72081A&quot; width=&quot;900&quot; height=&quot;784&quot; filename=&quot;7.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;빌드가 끝나면, 앞서 세팅해두었던 S3에 art&lt;/span&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;fact가 저장되어있다. 완료~!&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/250F6448584F42CE28&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F250F6448584F42CE28&quot; width=&quot;900&quot; height=&quot;127&quot; filename=&quot;8.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin-top: 2em; margin-right: 0px; margin-bottom: 0.5em; border-bottom: 1px solid rgb(145, 150, 153);&quot;&gt;삽질내용, &amp;nbsp;앞으로 AWS CodeDeploy 연동&amp;nbsp;&lt;/h2&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;buildspec.yml 을 정의하지 않고&amp;nbsp;커맨드라인으로 빌드 스크립트를 작성했더니, 빌드 완료 후 S3에 올릴 artifact를 찾지 못했다.&lt;/div&gt;&lt;div&gt;pom에 등록된 의존성 중에서 oracle 관련한 라이브러리를 가져오지 못했다. -&amp;gt; pom에 레파지토리 추가.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;이제 CodeDeploy를 이용하여 무중단 자동 배포만 준비하면 된다.&amp;nbsp;&lt;/div&gt;&lt;div&gt;Jenkins를 알고 CodeBuild를 설정해서 그런지, 무척이나 쉽게 느껴졌다.&lt;/div&gt;&lt;div&gt;하루빨리 Seoul 리전에도 서비스 되길!&amp;nbsp;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>AWS</category>
      <category>auto build</category>
      <category>AWS</category>
      <category>aws codebuild</category>
      <category>codebuild</category>
      <category>빌드 자동화</category>
      <category>빌드서버</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/5</guid>
      <comments>https://bkim.tistory.com/5#entry5comment</comments>
      <pubDate>Mon, 12 Dec 2016 18:46:55 +0900</pubDate>
    </item>
    <item>
      <title>JDBC에서 Batch Processing 이란? (Mybatis 연동)</title>
      <link>https://bkim.tistory.com/4</link>
      <description>&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;목적&lt;br /&gt;&lt;/h2&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;Spring + Mybatis로 구성된 서비스를 운영하던 중&amp;nbsp;사용자가 몰렸을 때 DB에 부담을 덜어주기 위한 방법을 고민했다.&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;Mybatis 의 ExcutorType 을 Batch로 설정하면 성능이 향상 되었는데 이유를 파악하기 위해 포스트 남긴다.&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;결론적으로 Batch 는 statement를 재사용 하며&amp;nbsp;Create, Insert, Update를 벌크로 모아서 처리하고,&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;Select를 만나면 기존에 모아놓았던 쿼리들을&amp;nbsp;&lt;span style=&quot;line-height: 1.8;&quot;&gt;수행하기 때문에 C, I, U 작업은 연달아서 할 때 가장 효율적이었다.&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;트랜잭션과, select문이 끼어드는 위치를 잘 조정하여 사용하면 &amp;nbsp;DB의 부담을&amp;nbsp;덜&amp;nbsp;수 있을것으로 보인다.&amp;nbsp;&lt;/div&gt;&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;Batch Processing? -&amp;nbsp;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC&quot; mce_href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC&quot; class=&quot;external-link&quot; rel=&quot;nofollow&quot; linktype=&quot;raw&quot; wikidestination=&quot;https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC&quot; aliasspecified=&quot;true&quot; style=&quot;color: rgb(0, 109, 175); outline: none;&quot;&gt;wiki&lt;/a&gt;&lt;/h2&gt;&lt;div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;일괄 처리(batch processing)란 컴퓨터 프로그램 흐름에 따라 순차적으로 자료를 처리하는 방식을 뜻한다.&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;일괄 처리 시스템(batch system)이란 일괄처리(batch processing) 방식이 적용된 시스템으로서, 하나의 작업이 끝나기 전까지는 다른 작업을 할 수 없다.&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;b&gt;장점&amp;nbsp;&lt;/b&gt;&lt;/div&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li style=&quot;line-height: 1.8;&quot;&gt;많은 사용자 사이에서 컴퓨터 자원을 공유할 수 있다.&lt;/li&gt;&lt;li style=&quot;line-height: 1.8;&quot;&gt;작업 프로세스의 시간대를 컴퓨터 리소스가 덜 사용되는 시간대로 이동한다.&lt;/li&gt;&lt;li style=&quot;line-height: 1.8;&quot;&gt;분 단위의 사용자 응답 대기와 더불어 컴퓨터 리소스의 유휴 사용을 피한다.&lt;/li&gt;&lt;li style=&quot;line-height: 1.8;&quot;&gt;전반적인 이용률을 높임으로써 컴퓨터의 비용을 더 잘 상환하도록 도와 준다.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;JDBC%EC%97%90%EC%84%9CBatchProcessing%EC%9D%B4%EB%9E%80%3F%28Mybatis%EC%97%B0%EB%8F%99%29-JDBC%EC%97%90%EC%84%9CBatchProcessing%26nbsp%3B&quot;&gt;&lt;/a&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;JDBC에서 Batch Processing&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;&lt;div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;JDBC 2.0는 batch proccessing 은 다음과 같이 제공한다.&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;1. Prepare statement.&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;2. Bind parameters.&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;3. Add to batch.&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;4. Repeat steps 2 and 3 until interest has been assigned for each account.&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;5. Execute.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 1.8;&quot;&gt;&lt;p style=&quot;margin: 10px 0px; font-size: 13.3333px; line-height: 1.8; color: rgb(51, 51, 51); padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;b style=&quot;font-size: 13.3333px; line-height: 17.3333px; background-color: initial;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;preparedStatement를 사용한 Batch Processing&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;wysiwyg-macro&quot; macroname=&quot;code&quot; macrostarttag=&quot;{code}&quot; macrohasbody=&quot;true&quot; wikihasnewlinebeforebody=&quot;true&quot; wikihasnewlineafterbody=&quot;true&quot; wikihasprecedingnewline=&quot;true&quot; wikihastrailingnewline=&quot;true&quot; style=&quot;color: rgb(51, 51, 51); font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13.3333px; line-height: 17.3333px;&quot;&gt;&lt;div class=&quot;code panel&quot; mce_style=&quot;border-width: 1px;&quot; style=&quot;color: black; padding: 0px; margin: 0px 0px 10px; border: 1px dashed rgb(187, 187, 187); overflow: auto; border-radius: 5px; background: rgb(240, 240, 240);&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot; style=&quot;color: rgb(51, 51, 51); margin: 0px; padding: 0px 10px; font-size: 0.95em; background: none;&quot;&gt;&lt;pre class=&quot;theme: Confluence; brush: java; gutter: false&quot; style=&quot;padding: 0px; margin-top: 0px; margin-bottom: 0px; overflow: auto; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; line-height: 1.3;&quot;&gt;PreparedStatement stmt = conn.prepareStatement(
&amp;nbsp; &amp;nbsp; &quot;UPDATE account SET balance = ? WHERE acct_id = ?&quot;);&quot;UPDATE account SET balance = ? WHERE acct_id = ?&quot;);
int[] rows;

for(int i=0; i&amp;lt;accts.length; i++) {
    accts[i].calculateInterest( );
    stmt.setDouble(1, accts[i].getBalance( ));
    stmt.setLong(2, accts[i].getID( ));
    stmt.addBatch( );
}
rows = stmt.executeBatch( );&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;li style=&quot;font-size: 10pt; line-height: 13pt; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;addBatch() : create, insert, update, deleted 일괄 처리 결과를 관리 할 필요가 없기 때문에 batch에 statement를 추가하는 일만 한다.&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;font-size: 10pt; line-height: 13pt; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;excuteBatch()가 쿼리들을 수행하고 정수형 배열을 리턴하는데, 각 배열의 요소는 각 statement로 인해 update된 row의 숫자이다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;wysiwyg-macro&quot; macroname=&quot;info&quot; macrohasbody=&quot;true&quot; wikihasprecedingnewline=&quot;true&quot; wikihastrailingnewline=&quot;true&quot;&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(121, 165, 228); padding: 10px; background-color: rgb(219, 232, 251);&quot;&gt;&lt;div class=&quot;wysiwyg-macro-tag wysiwyg-macro-starttag&quot;&gt;&lt;div class=&quot;wysiwyg-macro-tag wysiwyg-macro-starttag&quot;&gt;&lt;font color=&quot;#333333&quot; face=&quot;Arial, Helvetica, FreeSans, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 13.3333px; line-height: 17.3333px; font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;batch모드로 수행할 때 auto-commit을 사용하면 각각의 statement 를 수행 후 commit이 발생한다.&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;&lt;div class=&quot;wysiwyg-macro-tag wysiwyg-macro-starttag&quot;&gt;&lt;span style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51);&quot;&gt;그래서 batch 수행 중 에러가 발생하면 에러 발생 전까지 statement는 DB 에 반영되어있고 BatchUpdateException에서 getUpdateCounts()로&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(51, 51, 51); font-size: 13.3333px; line-height: 17.3333px;&quot;&gt;성공한 쿼리의 숫자를 얻어 올 수 있다.&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;wysiwyg-macro-tag wysiwyg-macro-starttag&quot;&gt;&lt;span style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51);&quot;&gt;실제 배치 과정에서, 각 statement 마다 commit을 하면 배치의 성능이 떨어지게 되는데 이것을 트랜잭션으로 묶어서 관리하려고 해도 성능에 악영향을 미친다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51);&quot;&gt;가장 좋은 방법은 임의의 수 만큼 statement 를 묶어서, 명시적으로 commit 하는 것 같다.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;wysiwyg-macro-body&quot; style=&quot;color: rgb(51, 51, 51); font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13.3333px; line-height: 17.3333px;&quot;&gt;&lt;p style=&quot;font-size: 10pt; line-height: 13pt; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; padding: 0px; background: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;JDBC%EC%97%90%EC%84%9CBatchProcessing%EC%9D%B4%EB%9E%80%3F%28Mybatis%EC%97%B0%EB%8F%99%29-MybatisBatchMode&quot;&gt;&lt;/a&gt;Mybatis Batch Mode&lt;/h2&gt;&lt;p style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); margin: 10px 0px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;Mybatis는 SqlSessionFactory에서 SqlSessionTemplate(SqlSession 구현체)을 생성할 때 ExcutorType을 지정해 줄 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;table class=&quot;confluenceTable&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); clear: left; margin: 1px; border-collapse: collapse; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background: none;&quot;&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-color: rgb(240, 240, 240);&quot;&gt;ExcutorType&lt;/th&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-color: rgb(240, 240, 240);&quot;&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background: none;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background: none;&quot;&gt;SIMPLE&lt;/td&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background: none;&quot;&gt;executor does nothing special&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background: none;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background: none;&quot;&gt;REUSE&lt;/td&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background: none;&quot;&gt;executor reuses prepared statements&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background: none;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background: none;&quot;&gt;BATCH&lt;/td&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background: none;&quot;&gt;executor reuses statements and batches updates&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); margin: 10px 0px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;br class=&quot;atl-forced-newline&quot;&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; background: none;&quot;&gt;&lt;span style=&quot;background-color: initial; line-height: 23.4px;&quot;&gt;&lt;b&gt;ExecutorType.BATCH&amp;nbsp;&lt;/b&gt;: 이 실행자는 모든 update(C,I,U,D)구문을 배치처리하고 중간에 select 가 실행될 경우 필요하다면 &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;경계&lt;/span&gt;를 표시한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; background: none;&quot;&gt;&lt;span style=&quot;line-height: 23.4px;&quot;&gt;여기서 이 경계는 아래 소스코드를 통해 확인 할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; background: none;&quot;&gt;&lt;span style=&quot;line-height: 23.4px; background-color: initial;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; background: none;&quot;&gt;&lt;span style=&quot;line-height: 23.4px; background-color: initial;&quot;&gt;SqlSessionTemplate에서 ExecutorType이 BATCH인 경우에 Create, Insert, Update, Delete 구문은 doUpdate 에서, Select 구문은 doQuery 에서 처리한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; background: none;&quot;&gt;&lt;span style=&quot;line-height: 23.4px; background-color: initial;&quot;&gt;아래 코드의 59번 줄에서 statement를 재사용하는 로직을 확인 할 수 있고, 61번, 69번 줄에서 statement 재사용 여부에 따라 statementList에 statement를 추가하고&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;line-height: 23.4px; background-color: initial;&quot;&gt;63번, 70번 줄에서 파라미터 추가, 다른 구문일 경우 BatchResult를 추가하는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; background: none;&quot;&gt;&lt;span style=&quot;line-height: 23.4px; background-color: initial;&quot;&gt;그리고 doQuery 메소드의 81번줄에서 flushStatements()를 호출 하는데, 이는 그동안 statementList에 쌓아 왔던 statement를 &amp;nbsp;executeBatch() 메소드로 수행한다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;line-height: 23.4px; background-color: initial;&quot;&gt;수행 결과는 batchResult에 저장하여 return 하고, 그동안 쌓아왔던 statementList 와 batchResultList 를 초기화한다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; background: none;&quot;&gt;&lt;span style=&quot;line-height: 23.4px; background-color: initial;&quot;&gt;아래 코드처럼 Select문이 실행 될 경우 BATCH 처리를 멈추고 초기화 하기 때문에, BATCH 작업 도중 SELECT 문이 끼어들면 성능이 저하된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; line-height: 1.8; background: none;&quot;&gt;&lt;font color=&quot;#333333&quot; face=&quot;Arial, Helvetica, FreeSans, sans-serif&quot;&gt;&lt;/font&gt;&lt;/p&gt;&lt;p style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); margin: 10px 0px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;br class=&quot;atl-forced-newline&quot;&gt;&lt;/p&gt;&lt;p style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); margin: 10px 0px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;b&gt;org.apache.ibatis.executor.BatchExecutor.class -&lt;/b&gt;&amp;nbsp;&lt;b&gt;&lt;a href=&quot;http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.7/org/apache/ibatis/executor/BatchExecutor.java#BatchExecutor&quot; mce_href=&quot;http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.7/org/apache/ibatis/executor/BatchExecutor.java#BatchExecutor&quot; class=&quot;external-link&quot; rel=&quot;nofollow&quot; linktype=&quot;raw&quot; wikidestination=&quot;http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.7/org/apache/ibatis/executor/BatchExecutor.java#BatchExecutor&quot; aliasspecified=&quot;true&quot; style=&quot;color: rgb(0, 109, 175); outline: none;&quot;&gt;grepcode&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;div class=&quot;wysiwyg-macro&quot; macroname=&quot;code&quot; macrostarttag=&quot;{code}&quot; macrohasbody=&quot;true&quot; wikihasnewlinebeforebody=&quot;true&quot; wikihasnewlineafterbody=&quot;true&quot; wikihasprecedingnewline=&quot;true&quot; wikihastrailingnewline=&quot;true&quot; style=&quot;color: rgb(51, 51, 51); font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13.3333px; line-height: 17.3333px;&quot;&gt;&lt;div class=&quot;code panel&quot; mce_style=&quot;border-width: 1px;&quot; style=&quot;color: black; padding: 0px; margin: 0px 0px 10px; border: 1px dashed rgb(187, 187, 187); overflow: auto; border-radius: 5px; background: rgb(240, 240, 240);&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot; style=&quot;color: rgb(51, 51, 51); margin: 0px; padding: 0px 10px; font-size: 0.95em; background: none;&quot;&gt;&lt;pre class=&quot;theme: Confluence; brush: java; gutter: false&quot; style=&quot;padding: 0px; margin-top: 0px; margin-bottom: 0px; overflow: auto; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; line-height: 1.3;&quot;&gt;40 public class More ...BatchExecutor extends BaseExecutor {
41
42   public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;
43
44   private final List&amp;lt;Statement&amp;gt; statementList = new ArrayList&amp;lt;Statement&amp;gt;();
45   private final List&amp;lt;BatchResult&amp;gt; batchResultList = new ArrayList&amp;lt;BatchResult&amp;gt;();
46   private String currentSql;
47   private MappedStatement currentStatement;
48
49   public More ...BatchExecutor(Configuration configuration, Transaction transaction) {
50     super(configuration, transaction);
51   }
52
53   public int More ...doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
54     final Configuration configuration = ms.getConfiguration();
55     final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
56     final BoundSql boundSql = handler.getBoundSql();
57     final String sql = boundSql.getSql();
58     final Statement stmt;
59     if (sql.equals(currentSql) &amp;amp;&amp;amp; ms.equals(currentStatement)) {
60       int last = statementList.size() - 1;
61       stmt = statementList.get(last);
62       BatchResult batchResult = batchResultList.get(last);
63       batchResult.addParameterObject(parameterObject);
64     } else {
65       Connection connection = getConnection(ms.getStatementLog());
66       stmt = handler.prepare(connection);
67       currentSql = sql;
68       currentStatement = ms;
69       statementList.add(stmt);
70       batchResultList.add(new BatchResult(ms, sql, parameterObject));
71     }
72     handler.parameterize(stmt);
73     handler.batch(stmt);
74     return BATCH_UPDATE_RETURN_VALUE;
75   }
76
77   public &amp;lt;E&amp;gt; List&amp;lt;E&amp;gt; More ...doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
78       throws SQLException {
79     Statement stmt = null;
80     try {
81       flushStatements();
82       Configuration configuration = ms.getConfiguration();
83       StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
84       Connection connection = getConnection(ms.getStatementLog());
85       stmt = handler.prepare(connection);
86       handler.parameterize(stmt);
87       return handler.&amp;lt;E&amp;gt;query(stmt, resultHandler);
88     } finally {
89       closeStatement(stmt);
90     }
91   }
92
93   public List&amp;lt;BatchResult&amp;gt; More ...doFlushStatements(boolean isRollback) throws SQLException {
94     try {
95       List&amp;lt;BatchResult&amp;gt; results = new ArrayList&amp;lt;BatchResult&amp;gt;();
96       if (isRollback) {
97         return Collections.emptyList();
98       } else {
99         for (int i = 0, n = statementList.size(); i &amp;lt; n; i++) {
100          Statement stmt = statementList.get(i);
101          BatchResult batchResult = batchResultList.get(i);
102          try {
103            batchResult.setUpdateCounts(stmt.executeBatch());
104            MappedStatement ms = batchResult.getMappedStatement();
105            List&amp;lt;Object&amp;gt; parameterObjects = batchResult.getParameterObjects();
106            KeyGenerator keyGenerator = ms.getKeyGenerator();
107            if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
108              Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
109              jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
110            } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
111              for (Object parameter : parameterObjects) {
112                keyGenerator.processAfter(this, ms, stmt, parameter);
113              }
114            }
115          } catch (BatchUpdateException e) {
116            StringBuffer message = new StringBuffer();
117            message.append(batchResult.getMappedStatement().getId())
118                .append(&quot; (batch index #&quot;)
119                .append(i + 1)
120                .append(&quot;)&quot;)
121                .append(&quot; failed.&quot;);
122            if (i &amp;gt; 0) {
123              message.append(&quot; &quot;)
124                  .append(i)
125                  .append(&quot; prior sub executor(s) completed successfully, but will be rolled back.&quot;);
126            }
127            throw new BatchExecutorException(message.toString(), e, results, batchResult);
128          }
129          results.add(batchResult);
130        }
131        return results;
132      }
133    } finally {
134      for (Statement stmt : statementList) {
135        closeStatement(stmt);
136      }
137      currentSql = null;
138      statementList.clear();
139      batchResultList.clear();
140    }
141  }
142
143}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;h6 style=&quot;padding: 0px; font-size: 1em; margin: 1em 0px 0.1em; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;JDBC%EC%97%90%EC%84%9CBatchProcessing%EC%9D%B4%EB%9E%80%3F%28Mybatis%EC%97%B0%EB%8F%99%29-&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;/h6&gt;&lt;h2 style=&quot;padding: 0px 0px 2px; font-size: 1.6em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;JDBC%EC%97%90%EC%84%9CBatchProcessing%EC%9D%B4%EB%9E%80%3F%28Mybatis%EC%97%B0%EB%8F%99%29-%26nbsp%3B%EA%B8%B0%ED%83%80%2C%EC%B0%B8%EC%A1%B0&quot;&gt;&lt;/a&gt;&amp;nbsp;기타, 참조&lt;/h2&gt;&lt;h5 style=&quot;padding: 0px; font-size: 1.1em; margin: 1em 0px 0.1em; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;JDBC%EC%97%90%EC%84%9CBatchProcessing%EC%9D%B4%EB%9E%80%3F%28Mybatis%EC%97%B0%EB%8F%99%29-%EC%9A%A9%EC%96%B4&quot;&gt;&lt;/a&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 11pt;&quot;&gt;&lt;br /&gt;용어&lt;/span&gt;&lt;/h5&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(121, 165, 228); padding: 10px; background-color: rgb(219, 232, 251);&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;SqlSessionTemplate - http://www.mybatis.org/spring/ko/sqlsession.html&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;SqlSessionTemplate은 마이바티스 스프링 연동모듈의 핵심이다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;SqlSessionTemplate은 SqlSession을 구현하고 코드에서 SqlSession를 대체하는 역할을 한다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;SqlSessionTemplate 은 쓰레드에 안전하고 여러개의 DAO나 매퍼에서 공유할수 있다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;getMapper()에 의해 리턴된 매퍼가 가진 메서드를 포함해서 SQL을 처리하는 마이바티스 메서드를 호출할때 SqlSessionTemplate은 SqlSession이 현재의 스프링 트랜잭션에서 사용될수 있도록 보장한다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;추가적으로 SqlSessionTemplate은 필요한 시점에 세션을 닫고, 커밋하거나 롤백하는 것을 포함한 세션의 생명주기를 관리한다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;또한 마이바티스 예외를 스프링의 DataAccessException로 변환하는 작업또한 처리한다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;SqlSessionTemplate은 마이바티스의 디폴트 구현체인 DefaultSqlSession 대신 항상 사용된다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;왜냐하면 템플릿은 스프링 트랜잭션의 일부처럼 사용될 수 있고 여러개 주입된 매퍼 클래스에 의해 사용되도록 쓰레드에 안전하다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 10pt;&quot;&gt;동일한 애플리케이션에서 두개의 클래스간의 전환은 데이터 무결성 이슈를 야기할수 있다.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;wysiwyg-macro&quot; macroname=&quot;info&quot; macrohasbody=&quot;true&quot; wikihasprecedingnewline=&quot;true&quot; wikihastrailingnewline=&quot;true&quot; style=&quot;color: rgb(51, 51, 51); font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13.3333px; line-height: 17.3333px;&quot;&gt;&lt;div class=&quot;wysiwyg-macro-tag wysiwyg-macro-starttag&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;wysiwyg-macro-tag wysiwyg-macro-endtag&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif; font-size: 1.1em; color: rgb(0, 0, 0); line-height: normal;&quot;&gt;&lt;b&gt;참조&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); margin: 10px 0px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;Batch Processing -&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC&quot; mce_href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC&quot; class=&quot;external-link&quot; rel=&quot;nofollow&quot; linktype=&quot;raw&quot; wikidestination=&quot;https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC&quot; originalalias=&quot;https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC&quot; style=&quot;color: rgb(0, 109, 175); outline: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); margin: 10px 0px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;Batch Processing(JDBC) -&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.safaribooksonline.com/library/view/database-programming-with/1565926161/ch04s02.html&quot; mce_href=&quot;https://www.safaribooksonline.com/library/view/database-programming-with/1565926161/ch04s02.html&quot; class=&quot;external-link&quot; rel=&quot;nofollow&quot; linktype=&quot;raw&quot; wikidestination=&quot;https://www.safaribooksonline.com/library/view/database-programming-with/1565926161/ch04s02.html&quot; originalalias=&quot;https://www.safaribooksonline.com/library/view/database-programming-with/1565926161/ch04s02.html&quot; style=&quot;color: rgb(0, 109, 175); outline: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;https://www.safaribooksonline.com/library/view/database-programming-with/1565926161/ch04s02.html&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); margin: 10px 0px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;Batch Processing(JDBC) -&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm&quot; mce_href=&quot;http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm&quot; class=&quot;external-link&quot; rel=&quot;nofollow&quot; linktype=&quot;raw&quot; wikidestination=&quot;http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm&quot; originalalias=&quot;http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm&quot; style=&quot;color: rgb(0, 109, 175); outline: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); margin: 10px 0px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;Mybatis3 -&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://www.mybatis.org/mybatis-3/ko/index.html&quot; mce_href=&quot;http://www.mybatis.org/mybatis-3/ko/index.html&quot; class=&quot;external-link&quot; rel=&quot;nofollow&quot; linktype=&quot;raw&quot; wikidestination=&quot;http://www.mybatis.org/mybatis-3/ko/index.html&quot; originalalias=&quot;http://www.mybatis.org/mybatis-3/ko/index.html&quot; style=&quot;color: rgb(0, 109, 175); outline: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;http://www.mybatis.org/mybatis-3/ko/index.html&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;font-size: 13.3333px; line-height: 17.3333px; color: rgb(51, 51, 51); margin: 10px 0px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;Grep Code(org.apache.ibatis.executor.BatchExecutor.class) -&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.7/org/apache/ibatis/executor/BatchExecutor.java#BatchExecutor&quot; mce_href=&quot;http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.7/org/apache/ibatis/executor/BatchExecutor.java#BatchExecutor&quot; class=&quot;external-link&quot; rel=&quot;nofollow&quot; linktype=&quot;raw&quot; wikidestination=&quot;http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.7/org/apache/ibatis/executor/BatchExecutor.java#BatchExecutor&quot; originalalias=&quot;http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.7/org/apache/ibatis/executor/BatchExecutor.java#BatchExecutor&quot; style=&quot;color: rgb(0, 109, 175); outline: none;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;맑은 고딕&amp;quot;, sans-serif;&quot;&gt;http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.7/org/apache/ibatis/executor/BatchExecutor.java#BatchExecutor&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <category>DATA</category>
      <category>Batch</category>
      <category>JDBC</category>
      <category>mybatis</category>
      <category>mybatis batch performance</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/4</guid>
      <comments>https://bkim.tistory.com/4#entry4comment</comments>
      <pubDate>Tue, 21 Jun 2016 18:29:38 +0900</pubDate>
    </item>
    <item>
      <title>Spring long polling(Async Servlet) 이용하여 응답지연 서버 만들기</title>
      <link>https://bkim.tistory.com/3</link>
      <description>&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;1. 개요&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;hr style=&quot;display:block; border: black 0 none; border-top: black 1px solid; height: 1px&quot;&gt;&lt;/div&gt;&lt;p&gt;서비스에 대용량의 트래픽이 몰리면서, 특정 API&amp;nbsp;호출에 대한 응답이 지연되면&amp;nbsp;전체적 로직에 영향을 미치게 된다.&lt;/p&gt;&lt;p&gt;이러한 상황을 재현하기 위해 응답을 늦게 보내는 서버를 구현 하고자 했다.&lt;/p&gt;&lt;p&gt;단순하게 요청을 받고 몇초간의 sleep 후 응답을 돌려주면 간단하게 구현할 수 있지만,&amp;nbsp;&lt;/p&gt;&lt;p&gt;제한된 자원(톰캣 1대)에서 다수(초당 15000명)의 request 를 처리하기 위해서 일반적인 sleep 방법으로는 구현 할 수 없었다.&lt;/p&gt;&lt;p&gt;(성능 이슈가 없다면&amp;nbsp;&lt;a href=&quot;http://www.seanshadmand.com/2012/06/21/fake-response-server-slow-response-time-generator/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;이곳&lt;/a&gt; 을 참조하면 간단하게 응답 지연 api를 얻을 수 있다.)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;2. 문제점&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;hr style=&quot;display:block; border: black 0 none; border-top: black 1px solid; height: 1px&quot;&gt;&lt;/div&gt;&lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;사실, response time은&amp;nbsp;늦으면서, 다수의 request를 처리한다는 건 역설적인 말이다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;request 가 많을 수록, connection 의 수는 늘어 날 것이고, sleep 을 통해 connection을 놓아주지 않으면 &amp;nbsp;더 이상의 request 를 처리할 수 없기 때문이다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;request 를 위한 connection 비용이 적지 않을 뿐더러, Spring 에서 request 를 처리하기 위한 servlet&amp;nbsp;container thread 자원은 application의 로직을&lt;/p&gt;&lt;p&gt;수행하기 위한&amp;nbsp;application&amp;nbsp;thread 보다 적고&amp;nbsp;한정적이다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;3. 해결 방법&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;hr style=&quot;display:block; border: black 0 none; border-top: black 1px solid; height: 1px&quot;&gt;&lt;/div&gt;&lt;p&gt;Long polling 방식으로 request 에 대하여 늦은 response를 전달하는 방법으로 서버 성능 문제를 해결하고자 했다.&lt;/p&gt;&lt;p&gt;단순히 클라이언트 쪽에서 long polling 방식은 connection을 그대로 유지하고 있기 때문에 문제를 해결 할 수 없는 방식이었고,&lt;/p&gt;&lt;p&gt;서버쪽에서 long polling 을 적용하여 connection 위한 thread 관리가 필요했다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;사실 long polling 방식도 request - response 모델이어서, 서버에서&amp;nbsp;클라이언트에게 응답을 주기 전까지 connection을&lt;/p&gt;&lt;p&gt;유지하기 때문에 이 방식도 성능 이슈를 해결하기 어려울 것 처럼 보였다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;그러던 중 이러한 long polling의 문제점을 보완하기 위해&amp;nbsp;Spring 3.2에서 추가된&amp;nbsp;Async Servlet 기능을 보게 되었다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Async Servlet는 request 처리를 위한 servlet container&amp;nbsp;thread의 일을&amp;nbsp;application thread에&amp;nbsp;위임시키고&amp;nbsp;servlet container&amp;nbsp;thread를 반납해서&lt;/p&gt;&lt;p&gt;새로운 request 를 처리하는 방식으로 작동한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Spring 의 Async Servlet 을 이용하면, 서버의 thread pool 과 acceptCount 값을 조정하여,&amp;nbsp;&lt;/p&gt;&lt;p&gt;제한된 자원에서 다수의 request 를 처리할 수 있을것이라 생각했다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;4. 적용&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;hr style=&quot;display:block; border: black 0 none; border-top: black 1px solid; height: 1px&quot;&gt;&lt;/div&gt;&lt;p&gt;소스 코드는 &lt;a href=&quot;https://github.com/SpringSource/spring-mvc-showcase/blob/master/src/main/java/org/springframework/samples/mvc/async/CallableController.java&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Spring-mvc-showcase&lt;/a&gt; 를 참조하였다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;(1) 소스&lt;/p&gt;
&lt;pre class=&quot;brush:java&quot;&gt;&lt;p&gt;@Controller
@RequestMapping(&quot;/async/callable&quot;)
public class CallableController {


    @RequestMapping(&quot;/response-body-2&quot;)
    public @ResponseBody Callable&amp;lt;String&amp;gt; callable() {

        return new Callable&amp;lt;String&amp;gt;() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                return &quot;Callable result&quot;;
            }
        };
    }
}
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;(2) 결과&lt;/p&gt;&lt;p style=&quot;text-align: left;&quot;&gt;응답이 2초 후 온 것을 알 수 있다.&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 681px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/274E993856515F9213&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F274E993856515F9213&quot; width=&quot;681&quot; height=&quot;286&quot; filename=&quot;지연.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;위 로직을 수행하는 동안의 로그는 다음과 같다.&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;15:23:20 [http-apr-80-exec-9] DispatcherServlet - DispatcherServlet with name 'appServlet' processing GET request for [/async/callable/response-body-2]&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;15:23:20 [http-apr-80-exec-9] RequestMappingHandlerMapping - Looking up handler method for path /async/callable/response-body-2&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;15:23:20 [http-apr-80-exec-9] RequestMappingHandlerMapping - Returning handler method [public java.util.concurrent.Callable&amp;lt;java.lang.String&amp;gt; org.springframework.samples.mvc.async.CallableController.callable()]&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;15:23:20 [http-apr-80-exec-9] DispatcherServlet - Last-Modified value for [/async/callable/response-body-2] is: -1&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;b&gt;여기 까지 기존 로직을 따른다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;span style=&quot;color: rgb(255, 255, 255); background-color: rgb(255, 0, 0);&quot;&gt;15:23:20 [http-apr-80-exec-9] WebAsyncManager - Concurrent handling starting for GET [/async/callable/response-body-2]&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;b&gt;WebAsyncManager(application thread)&amp;nbsp;에서&amp;nbsp;병행처리를&amp;nbsp;시작하고&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;span style=&quot;color: rgb(255, 255, 255); background-color: rgb(255, 0, 0);&quot;&gt;15:23:20 [http-apr-80-exec-9] DispatcherServlet - Leaving response open for concurrent processing&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;b&gt;Dispatcher(servlet container thred) 에서 작업을 끝낸다.&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;b&gt;이렇게 작업 쓰레드간 switching 이 이루어지고&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;span style=&quot;color: rgb(255, 255, 255); background-color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 255, 255); background-color: rgb(255, 0, 0);&quot;&gt;15:23:22 [MvcAsync5] WebAsyncManager - Concurrent result value [Callable result] - dispatching request to resume processing&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;b style=&quot;color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;작업을 넘겨받은 MvcAsyc 는 작업을 수행(2초간의 sleep)후 dispatching 을 요청한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;15:23:22 [http-apr-80-exec-4] DispatcherServlet - DispatcherServlet with name 'appServlet' resumed processing GET request for [/async/callable/response-body-2]&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;15:23:22 [http-apr-80-exec-4] RequestMappingHandlerMapping - Looking up handler method for path /async/callable/response-body-2&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;15:23:22 [http-apr-80-exec-4] RequestMappingHandlerMapping - Returning handler method [public java.util.concurrent.Callable&amp;lt;java.lang.String&amp;gt; org.springframework.samples.mvc.async.CallableController.callable()]&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;15:23:22 [http-apr-80-exec-4] DispatcherServlet - Last-Modified value for [/async/callable/response-body-2] is: -1&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;span style=&quot;color: rgb(255, 255, 255); background-color: rgb(255, 0, 0);&quot;&gt;15:23:22 [http-apr-80-exec-4] RequestMappingHandlerAdapter - Found concurrent result value [Callable result]&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;span style=&quot;color: rgb(255, 255, 255); background-color: rgb(255, 0, 0);&quot;&gt;15:23:22 [http-apr-80-exec-4] RequestResponseBodyMethodProcessor - Written [Callable result] as &quot;text/html&quot; using [org.springframework.http.converter.StringHttpMessageConverter@7967f612]&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);&quot;&gt;Spring mvc가 callable 을 보고 병행작업임을 알고 나머지 로직을 수행한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;clear: none; float: none;&quot;&gt;15:23:22 [http-apr-80-exec-4] DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'appServlet': assuming HandlerAdapter completed request handling&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;15:23:22 [http-apr-80-exec-4] DispatcherServlet - Successfully completed request&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;5. Servlet container thread 와 application specific thread 의 차이&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;hr style=&quot;display:block; border: black 0 none; border-top: black 1px solid; height: 1px&quot;&gt;&lt;/div&gt;&lt;p&gt;여기서&amp;nbsp;servlet container thread 와 application&amp;nbsp;thread 의 차이점을 살펴보자.&lt;/p&gt;&lt;p&gt;servlet thread의 일을 application thread 로 넘겨줌으로 해서 long polling 의 단점을 보완한다고 하는데, 결국 application thread 역시&lt;/p&gt;&lt;p&gt;서버의 자원을 사용하지 않는가? 라는 의문을 가질 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Servlet container 란 HTTP Request 와 response 객체를 서블릿에 넘겨주고, 서블릿의 생명주기를 관리한다.&lt;/p&gt;&lt;p&gt;따라서 servlet container thread 는 사용자의 request 를 처리하는 작업을 수행한다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;반면 application는 서비스 자체를 의미하고, application thread는&amp;nbsp;Spring framework 에서 발생하는 작업들을 수행한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이러한 관점에서 보았을때, &amp;nbsp;serblet thread 의 일을 application thread 에 위임하는 것이&amp;nbsp;&lt;/p&gt;&lt;p&gt;많은 request 를 수신하기 위한 효율 적인 방법임을 알 수 있다.&lt;/p&gt;&lt;p&gt;하지만, 결국 한정된 서버의 자원을 공유하여 사용한다는것은 변함이 없다.&lt;/p&gt;&lt;p&gt;spring mvc 내에서 servlet container에 할당 할 thread 수를 조정할 수 있는지 알아보고 최적화가 필요할 것 같다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;6. 결론&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;hr style=&quot;display:block; border: black 0 none; border-top: black 1px solid; height: 1px&quot;&gt;&lt;/div&gt;&lt;p&gt;서버의 한정된 자원에서 다수의 request 를 처리하는데 한계가 있지만,&amp;nbsp;&lt;/p&gt;&lt;p&gt;서버는 무엇으로 구성할지 (톰캣, 네티, 직접구현)에 따라서, 그리고 서버 환경 설정을 어떻게 하는냐에 따라 동시에 수용할 수 있는 request의 수를 증가 시킬 수 있다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;서버의 설정 이후에는, 어플리케이션의 구현 부분에서 최적화가 필요할 것이다.&lt;/p&gt;&lt;p&gt;고민의 시작은 전자에서 시작했지만, 작업은 후자에서 진행되었다.&lt;/p&gt;&lt;p&gt;다시 서버단으로 돌아가서 고민을 해봐야겠지만, 넉넉한 자원이 주어졌을때, 해당 자원을 제대로 활용하지 못하는 경우&lt;/p&gt;&lt;p&gt;application의 구현부분에서의 최적화 역시 필요할것으로 생각한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;결과적으로 &amp;nbsp;Async Servlet를 이용한 long polling 방식으로&amp;nbsp;서버에 요청할 수 있는 최대 request 를 늘리는 것은 실패하였다.&lt;/p&gt;&lt;p&gt;추가적으로 서버의 최적화 또는, tomcat 에 comet 을 적용, 심플한 구조의 서버 구축과 같은 작업이 병행되어야 할 것으로 보인다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>SPRING</category>
      <category>Async Servlet</category>
      <category>Callable</category>
      <category>fake response</category>
      <category>Spring long polling</category>
      <category>응답지연 서버</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/3</guid>
      <comments>https://bkim.tistory.com/3#entry3comment</comments>
      <pubDate>Sun, 22 Nov 2015 14:55:18 +0900</pubDate>
    </item>
    <item>
      <title>Flyway 개념 &amp;amp; 사용법</title>
      <link>https://bkim.tistory.com/2</link>
      <description>&lt;h1 style=&quot;color: rgb(0, 0, 0); line-height: normal; padding: 0px 0px 2px; font-size: 1.8em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;Flyway?&lt;/span&gt;&lt;/h1&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;데이터베이스&amp;nbsp;형상관리 툴.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;로컬에서 변경한 데이터베이스의 스키마나 데이터를 운영 데이터베이스에 반영하는 것을 누락하는것을 막기 위해 사용한다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;또한 개발 DB와 운영 DB의 스키마를 비교하거나, 운영 DB에 수작업을 가하는 노가다와 위험성을 줄이기 위해 사용한다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;생성한 형상을 새로운 DB에 적용하면 그게 마이그레이션이다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;br style=&quot;margin: 0px; padding: 0px; clear: both;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; text-align: center; clear: none; float: none; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 740px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2540C342563AB3CD1F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2540C342563AB3CD1F&quot; width=&quot;740&quot; height=&quot;305&quot; filename=&quot;Environments.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h1 style=&quot;color: rgb(0, 0, 0); line-height: normal; padding: 0px 0px 2px; font-size: 1.8em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;Flyway%EA%B0%9C%EB%85%90%26%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%8F%99%EC%9E%91%EB%B0%A9%EC%8B%9D&quot; target=&quot;_blank&quot; class=&quot;con_link&quot;&gt;&lt;/a&gt;동작방식&lt;/h1&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;Flyway 가 연결된 데이터베이스에 자동으로 SCHEMA_VERSION 이라는 메타데이터 테이블을 생성한다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;Flyway 는 사용자가 정의한 sql의 파일명을 자동으로 스캔하여,&amp;nbsp;SCHEMA_VERSION 에 버전 정보를 남기는 동시에,&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;데이터베이스에 변경내용을 적용한다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;SCHEMA_VERSION 테이블에는 다음과 같은 정보를 담고 있다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; text-align: center; clear: none; float: none; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;span style=&quot;font-size: 13.3333px; line-height: 17.3333px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; text-align: center; clear: none; float: none; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 740px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/25192C43563AB40C10&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F25192C43563AB40C10&quot; width=&quot;740&quot; height=&quot;88&quot; filename=&quot;SchemaVersion-1-2.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;span style=&quot;font-size: 13.3333px; line-height: 17.3333px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;h1 style=&quot;color: rgb(0, 0, 0); line-height: normal; padding: 0px 0px 2px; font-size: 1.8em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;Flyway%EA%B0%9C%EB%85%90%26%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%AA%85%EB%A0%B9%EC%96%B4%EC%84%A4%EB%AA%85&quot; target=&quot;_blank&quot; class=&quot;con_link&quot;&gt;&lt;/a&gt;명령어 설명&lt;/h1&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;init -&amp;nbsp;SCHEMA_VERSION 을 baseline 과 함께 생성한다. 테이블이 이미 생성되어 있으면 수행되지 않는다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;migrate - 스키마정보를 리얼DB에 마이그레이션한다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;clean - flyway로 생성한 스키마를 모두 삭제한다고 하지만, 해당 데이터 베이스의 모든 테이블을 삭제한다.&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;info - DB에 적용된 스키마 정보와, 로컬에 pending 되어있는 변경 정보를 보여준다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;validate - DB에 적용된 스키마 정보와, 로컬의 변경점을 비교하여 보여준다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;repair - 마이그레이션 실패한 내역을 수정한다 (삭제, 교체)&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;baseline - flyway로 형상 버전관리를 시작 할 baseline 을 설정한다.&lt;/p&gt;&lt;h1 style=&quot;color: rgb(0, 0, 0); line-height: normal; padding: 0px 0px 2px; font-size: 1.8em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;Flyway%EA%B0%9C%EB%85%90%26%EC%82%AC%EC%9A%A9%EB%B2%95-Commandlinetool%EB%A1%9C%EC%98%88%EC%A0%9C%EC%8B%A4%ED%96%89&quot; target=&quot;_blank&quot; class=&quot;con_link&quot;&gt;&lt;/a&gt;Command-line tool 로 예제 실행&lt;/h1&gt;&lt;h6 style=&quot;color: rgb(0, 0, 0); line-height: normal; padding: 0px; font-size: 1em; margin: 1em 0px 0.1em; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;Flyway%EA%B0%9C%EB%85%90%26%EC%82%AC%EC%9A%A9%EB%B2%95-%281%29%EC%84%A4%EC%B9%98&quot; target=&quot;_blank&quot; class=&quot;con_link&quot;&gt;&lt;/a&gt;&lt;b&gt;(1) 설치&lt;/b&gt;&lt;/h6&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;a href=&quot;http://flywaydb.org/getstarted/firststeps/commandline.html&quot; class=&quot;con_link&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot; style=&quot;color: rgb(0, 109, 175); outline: none;&quot;&gt;http://flywaydb.org/getstarted/firststeps/commandline.html&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;b&gt;(2) 설정&lt;/b&gt;&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;설치 폴더 -&amp;gt; conf -&amp;gt; flyway.con 파일 수정 (C:\flyway\conf\flyway.conf)&lt;/p&gt;&lt;div class=&quot;wysiwyg-macro&quot; style=&quot;font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13.3333px; line-height: 17.3333px;&quot;&gt;&lt;div class=&quot;preformatted panel&quot; style=&quot;color: black; padding: 0px; margin: 0px 0px 10px; border: 1px solid rgb(187, 187, 187); overflow: hidden; border-radius: 5px; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;div class=&quot;preformattedContent panelContent&quot; style=&quot;color: rgb(51, 51, 51); margin: 0px; padding: 0px 10px; font-size: 0.95em; background: none;&quot;&gt;&lt;pre style=&quot;padding: 0px; margin-top: 0px; margin-bottom: 0px; overflow: auto; font-family: 'Courier New', Courier, monospace; line-height: 1.3;&quot;&gt;flyway.url=jdbc:mysql://localhost:3306/테이블명
flyway.user=아이디
flyway.password=비번&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;b&gt;(3) 마이그레이션 sql문 생성&lt;/b&gt;&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;설치 폴더 -&amp;gt; sql (C:\flyway\sql) 에 파일 생성.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;init을 이용하여 SCHEMA_VERSION 테이블을 생성하면 V1 로 생성되기 때문에 파일명을 V2 로 생성함.&lt;/p&gt;&lt;table class=&quot;confluenceTable __se_tbl_ext&quot; style=&quot;border-collapse: collapse; font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); clear: left; margin: 1px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-color: rgb(240, 240, 240);&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;V2__Create_person_table.sql&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;create table PERSON (&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; ID int not null,&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; NAME varchar(100) not null&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;);create table PERSON (&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; ID int not null,&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; NAME varchar(100) not null&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;); &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table class=&quot;confluenceTable __se_tbl_ext&quot; style=&quot;border-collapse: collapse; font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); clear: left; margin: 1px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-color: rgb(240, 240, 240);&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;V2.1__Insert_person.sql&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;insert into PERSON (ID, NAME) values (1, 'Axel');&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;insert into PERSON (ID, NAME) values (2, 'Mr. Foo');&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;insert into PERSON (ID, NAME) values (3, 'Ms. Bar');&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;파일명은 V 와 숫자로 버전명을 지정하고 under_bar 두개로 시작되어야한다. 이미지참조.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 389px; font-size: 13.3333px; line-height: 17.3333px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/220D4641563AB3E419&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F220D4641563AB3E419&quot; width=&quot;389&quot; height=&quot;213&quot; filename=&quot;SqlMigrationNaming.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;font-size: 13.3333px; line-height: 17.3333px; text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;b&gt;(4) flyway init 명령문 수행&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;flyway init 없이 migrate를 수행하면, 자동으로 schema_version이 생성된다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;flyway init 을 수행하면 결과 화면과 같이 baseline 이 V1 로 입력되어있는것을 확인 할 수 있다.&lt;/p&gt;&lt;table class=&quot;confluenceTable __se_tbl_ext&quot; style=&quot;border-collapse: collapse; font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); clear: left; margin: 1px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; width: 507px; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot; width=&quot;507&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; width: 506px; background-color: rgb(240, 240, 240);&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;명령문 수행화면&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; height: 150px; width: 506px; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 656px; font-size: 10pt; line-height: 13pt; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2477C341563AB43006&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2477C341563AB43006&quot; width=&quot;656&quot; height=&quot;135&quot; filename=&quot;init.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;font-size: 10pt; line-height: 13pt; text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; width: 506px; height: 28px; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;b&gt;데이터베이스 적용 결과&lt;/b&gt;&lt;/span&gt;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; height: 294px; width: 506px; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 740px; font-size: 10pt; line-height: 13pt; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2611403E563AB44E29&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2611403E563AB44E29&quot; width=&quot;740&quot; height=&quot;286&quot; filename=&quot;init_결과.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;font-size: 10pt; line-height: 13pt; text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;b&gt;(5) flyway migrate 명령문 수행&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;flyway가 sql 파일들을 스캐닝하여 수행한다.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;V2 와 V2.1 의 sql 파일이 버전 순서대로 수행된 것을 확인 할 수 있다.&lt;/p&gt;&lt;table class=&quot;confluenceTable __se_tbl_ext&quot; style=&quot;border-collapse: collapse; font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); clear: left; margin: 1px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; width: 752px; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot; width=&quot;752&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; width: 751px; background-color: rgb(240, 240, 240);&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;명령문 수행화면&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; height: 175px; width: 751px; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 694px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/23464F3E563AB46F19&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F23464F3E563AB46F19&quot; width=&quot;694&quot; height=&quot;168&quot; filename=&quot;migrate.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; width: 751px; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;b&gt;데이터베이스 적용결과&lt;/b&gt;&lt;/span&gt;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; width: 751px; height: 408px; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 740px; font-size: 10pt; line-height: 13pt;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/232DB740563AB49721&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F232DB740563AB49721&quot; width=&quot;740&quot; height=&quot;148&quot; filename=&quot;mig_결과_1.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;font-size: 10pt; line-height: 13pt;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 591px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/230E0E40563AB49807&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F230E0E40563AB49807&quot; width=&quot;591&quot; height=&quot;236&quot; filename=&quot;mig_결과_2.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;b&gt;(6) 마이그레이션 sql문 추가 생성&lt;/b&gt;&lt;/p&gt;&lt;table class=&quot;confluenceTable __se_tbl_ext&quot; style=&quot;border-collapse: collapse; font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); clear: left; margin: 1px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-color: rgb(240, 240, 240);&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;V2.2__Insert_another_person.sql&amp;nbsp;&lt;br class=&quot;atl-forced-newline&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;insert into PERSON (ID, NAME) values (5, 'CLEAN!!!!');&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;b&gt;(7) flyway validate 명령문 수행&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;migrate 없이, flyway validate 를 수행하면 새로 추가한 쿼리문에 실제 DB에 적용되어 있지않기 때문에,&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;fail이 떨어진다.&lt;/p&gt;&lt;table class=&quot;confluenceTable __se_tbl_ext&quot; style=&quot;border-collapse: collapse; font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); clear: left; margin: 1px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; height: 28px; background-color: rgb(240, 240, 240);&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;명령문 수행화면&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 656px; font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13.3333px; line-height: 17.3333px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/23555B44563AB4C721&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F23555B44563AB4C721&quot; width=&quot;656&quot; height=&quot;120&quot; filename=&quot;validate.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13.3333px; line-height: 17.3333px; text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;b&gt;(8)&lt;/b&gt;&amp;nbsp;&lt;b&gt;flyway&amp;nbsp;&lt;/b&gt;&lt;b&gt;info 명령문 수행&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;flyway info 로 &amp;nbsp;내용을 확인해 보면 2.2 버전의 파일이 pending 상태인것을 알 수 있다.&lt;/p&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;/p&gt;&lt;table class=&quot;confluenceTable __se_tbl_ext&quot; style=&quot;border-collapse: collapse; font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); clear: left; margin: 1px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; height: 28px; background-color: rgb(240, 240, 240);&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;명령문 수행화면&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 549px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/235B663F563AB50D19&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F235B663F563AB50D19&quot; width=&quot;549&quot; height=&quot;244&quot; filename=&quot;info.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;b&gt;(9) flyway clean 명령문 수행&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;flyway clean 을 수행하면 y/n 질문도 없이 데이터베이스의 모든 테이블들이 드랍된다.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;flyway로 작업된 테이블만 드랍된다는 말이 있는데, 아니다 모두 드랍된다.&lt;/span&gt;&lt;/p&gt;&lt;table class=&quot;confluenceTable __se_tbl_ext&quot; style=&quot;border-collapse: collapse; font-size: 10pt; line-height: 13pt; color: rgb(51, 51, 51); clear: left; margin: 1px; padding: 0px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;th class=&quot;confluenceTh&quot; style=&quot;font-size: 10pt; line-height: 13pt; color: rgb(0, 0, 0); padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-color: rgb(240, 240, 240);&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;명령문 수행화면&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 10pt; line-height: 13pt; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;td class=&quot;confluenceTd&quot; style=&quot;word-break: break-all; font-size: 10pt; line-height: 13pt; padding: 5px; border: 1px solid rgb(221, 221, 221); vertical-align: top; min-width: 0.6em; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 508px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/252F7B46563AB51927&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F252F7B46563AB51927&quot; width=&quot;508&quot; height=&quot;109&quot; filename=&quot;clean.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h1 style=&quot;color: rgb(0, 0, 0); line-height: normal; padding: 0px 0px 2px; font-size: 1.8em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;Flyway%EA%B0%9C%EB%85%90%26%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%83%9D%EA%B0%81&quot; target=&quot;_blank&quot; class=&quot;con_link&quot;&gt;&lt;/a&gt;생각&lt;/h1&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;전체적으로 사용하기 쉽고 대부분의 툴과 연동이 가능한 것이 장점.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;데이터 베이스의 스키마 변경 이력을 확인 할 수 있다는 점이 가장 좋았음.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;각자 로컬 데이터 베이스를 이용하여 개발하지 않으면 형상관리와 마이그레이션의 의미가 약해짐.&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;개발 DB 를 따로 운영함으로서, 작업중 스키마 변경에 따른 이슈가 발생 할 수 있지만,&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;스키마 이력관리를 위해, Flyway 를 적용하는 것은 오버스팩이라고 생각함.&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;margin: 10px 0px; padding: 0px; font-size: 13.3333px; line-height: 17.3333px; font-family: Arial, Helvetica, FreeSans, sans-serif; background-image: none; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;&quot;&gt;데이터베이스의 스키마를 변경하면 이력을 남기는 워크벤치쪽 플러그인이 있으면 좋겠다고 생각함.&lt;/p&gt;&lt;h1 style=&quot;color: rgb(0, 0, 0); line-height: normal; padding: 0px 0px 2px; font-size: 1.8em; margin: 2em 0px 0.5em; border-bottom-color: rgb(145, 150, 153); border-bottom-width: 1px; border-bottom-style: solid; font-family: Arial, Helvetica, FreeSans, sans-serif;&quot;&gt;&lt;a name=&quot;Flyway%EA%B0%9C%EB%85%90%26%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%B0%B8%EC%A1%B0&quot; target=&quot;_blank&quot; class=&quot;con_link&quot;&gt;&lt;/a&gt;참조&lt;/h1&gt;&lt;p style=&quot;margin-left: 0px;&quot;&gt;&lt;a href=&quot;http://flywaydb.org/&quot; class=&quot;con_link&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot; style=&quot;font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13.3333px; line-height: 17.3333px; color: rgb(0, 109, 175); outline: none;&quot;&gt;http://flywaydb.org/&lt;/a&gt;&lt;/p&gt;</description>
      <category>DATA</category>
      <category>Database</category>
      <category>database versioning</category>
      <category>flyway</category>
      <category>flywaydb</category>
      <category>데이터베이스</category>
      <category>형상관리</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/2</guid>
      <comments>https://bkim.tistory.com/2#entry2comment</comments>
      <pubDate>Thu, 5 Nov 2015 10:38:58 +0900</pubDate>
    </item>
    <item>
      <title>FUSE 를 이용하여 카메라 연동 테스트 앱 만들기</title>
      <link>https://bkim.tistory.com/1</link>
      <description>&lt;p style=&quot;margin-left: 0px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-size: 14pt; color: rgb(0, 0, 0); font-family: 맑은고딕, Dotum, 돋움;&quot; class=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;1.목적&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;div align=&quot;&quot; style=&quot;line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: 맑은고딕,  Dotum, 돋움;&quot;&gt; 
&lt;/span&gt;&lt;/div&gt;&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;FUSE 를 이용하여 Native Camera에 접근하여 사진을 찍고, 보여주고, 저장하는 앱을 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 0px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-size: 14pt; color: rgb(0, 0, 0); font-family: Dotum, 돋움;&quot;&gt;&lt;b&gt;2. 알아야 할 것&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;현재 FUSE 는 배타 환경으로 오픈하였기 때문에 NATIVE API가 빈약한 상태이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;구현에 들어가기 전 FUSE 에서 제공하는 API의 스펙을 확인하는 것을 추천한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;사용하려고 했던 API스펙&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;(1) Camera -&amp;nbsp;&lt;/span&gt;&lt;a target=&quot;_blank&quot; class=&quot;con_link&quot; href=&quot;https://www.fusetools.com/learn/fusejs#camera&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;https://www.fusetools.com/learn/fusejs#camera&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;Native Camera를 호출할 수 있는 API 다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;제공하는 함수는 takePicture 가 유일한데, 전달 값으로 너비와 높이, 방향이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;그러나 직접 구현해본 결과 전달 값과 상관없이 기본 카메라의 앵글로 촬영되었으며,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;이미지 생성도 기본 카메라와 동일한 크기로 작동하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 712px; font-size: 9pt; line-height: 1.5;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2362593B563ABA9C07&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2362593B563ABA9C07&quot; width=&quot;712&quot; height=&quot;322&quot; filename=&quot;takepc.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;font-size: 9pt; line-height: 1.5;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5; font-family: Dotum, 돋움;&quot;&gt;(2) Storage -&amp;nbsp;&lt;/span&gt;&lt;a target=&quot;_blank&quot; class=&quot;con_link&quot; href=&quot;https://www.fusetools.com/learn/fusejs#storage&quot; style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;https://www.fusetools.com/learn/fusejs#storage&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;Camera API 로 생성한 이미지를, 안드로이드 이미지 폴더에 복사(이동) 하기 위해 사용하려 했었던 API다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;하지만 상세 스펙을 보면&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움; font-size: 16px; line-height: 22.8571px; background-color: rgb(255, 255, 255);&quot;&gt;'The storage API allows you to save text to files in the application directory.'&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;라고 한다. 이미지를 저장해보려 테스트를 해보니, 에러를 뱉진 않았지만, 결과값이 에러 값을 저장하고 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;Camera로 생성한 이미지를 따로 저장하기 위해서는 다른 방법을 찾아봐야 할 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 0px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-size: 14pt; color: rgb(0, 0, 0); font-family: Dotum, 돋움;&quot;&gt;&lt;b&gt;3. 구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;(1) 화면 구성&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;ui구현이 목적이 아니기 때문에, FUSE 에서 제공한 &lt;/span&gt;&lt;a target=&quot;_blank&quot; class=&quot;con_link&quot; href=&quot;https://www.fusetools.com/community/examples/pagecontrol&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;Slides using PageControl&amp;nbsp;예제&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;를 수정하여 화면을 구성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;Style 과 assets 들은 예제와 같기 때문에 MainView.ux 코드만 첨부한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;MainView.ux&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;ol style=&quot;font-family: Consolas, 나눔고딕코딩, monospace, Arial; line-height: 19.2px; margin-top: 0px;&quot;&gt;&lt;ol style=&quot;font-family: Consolas, 나눔고딕코딩, monospace, Arial; line-height: 19.2px; margin-top: 0px;&quot;&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;lt;App Theme=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;Basic&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Background=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;#fff&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;DockPanel&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;MainStyle&amp;nbsp;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Page&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Info&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Header&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Text TextColor=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;#a94442&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Value=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;{myfilePath}&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Alignment=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;Center&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Text TextColor=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;#a94442&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Value=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;{errorMessage}&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Alignment=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;Center&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;/Header&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Button Text=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;Take a photo!!&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;ux:&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 0); font-family: Dotum, 돋움;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;button1&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Clicked=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;{myTakePicture}&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Button Text=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;Save a photo!!&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;ux:&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 0); font-family: Dotum, 돋움;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;button2&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Clicked=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;{mySavePicture}&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;/Info&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;BackgroundImage File=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;{myfilePath}&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;/Page&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;/DockPanel&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;lt;/App&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/ol&gt;&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;(2) Camera 연동&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;카메라 촬영 후, 화면에 표시하기 위해 Observable API와 함께 작성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;Camera.takePicture 의 너비와 높이 값은 결과물에 영향을 주지 못했고,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;line-height: 1.5; font-family: Dotum, 돋움;&quot;&gt;takePicture&lt;/span&gt;&lt;span style=&quot;line-height: 1.5; font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;가 리턴해주는&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;span style=&quot;line-height: 1.5; font-family: Dotum, 돋움;&quot;&gt;file 객체에서 path 를 꺼내 myFilePath 에 연결하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;span style=&quot;line-height: 1.5; font-family: Dotum, 돋움;&quot;&gt;(file 객체를 이용하여 storage 에 저장하려 했으나, 실패하였다.)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;2,3번 줄에서 사용할 객체 선언.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;8번째 줄에서 takePicture 함수 선언.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;16,19번 줄에서 모듈에 등록.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 5.3em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;MainView.ux&lt;/span&gt;&lt;/p&gt;&lt;ol style=&quot;font-family: Consolas, 나눔고딕코딩, monospace, Arial; line-height: 19.2px; margin-top: 0px;&quot;&gt;&lt;ol style=&quot;font-family: Consolas, 나눔고딕코딩, monospace, Arial; line-height: 19.2px; margin-top: 0px;&quot;&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;lt;App Theme=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;Basic&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Background=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;#fff&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;JavaScript&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255); font-family: Dotum, 돋움;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Observable&amp;nbsp;=&amp;nbsp;require&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;FuseJS/Observable&quot;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255); font-family: Dotum, 돋움;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Camera&amp;nbsp;=&amp;nbsp;require&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;'FuseJS/Camera'&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255); font-family: Dotum, 돋움;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;myfilePath&amp;nbsp;=&amp;nbsp;Observable&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255); font-family: Dotum, 돋움;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;myTakePicture&amp;nbsp;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255); font-family: Dotum, 돋움;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Camera.&lt;/span&gt;&lt;span style=&quot;color: rgb(102, 0, 102); font-family: Dotum, 돋움;&quot;&gt;takePicture&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;targetWidth:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(204, 0, 0); font-family: Dotum, 돋움;&quot;&gt;640&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;,&amp;nbsp;targetHeight:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(204, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;360&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: rgb(102, 0, 102); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; myfilePath.&lt;/span&gt;&lt;span style=&quot;color: rgb(102, 0, 102); font-family: Dotum, 돋움;&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;=&amp;nbsp;file.&lt;/span&gt;&lt;span style=&quot;color: rgb(102, 0, 102); font-family: Dotum, 돋움;&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 139); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot; class=&quot;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; console.&lt;/span&gt;&lt;span style=&quot;color: rgb(102, 0, 102); font-family: Dotum, 돋움;&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; module.&lt;/span&gt;&lt;span style=&quot;color: rgb(102, 0, 102); font-family: Dotum, 돋움;&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;=&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; myfilePath:&amp;nbsp;myfilePath,&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; myTakePicture:&amp;nbsp;myTakePicture&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0); font-family: Dotum, 돋움;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;/JavaScript&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;DockPanel&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;MainStyle&amp;nbsp;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Page&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Info&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Header&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Text TextColor=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;#a94442&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Value=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;{myfilePath}&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Alignment=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;Center&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;/Header&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;Button Text=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;Take a photo!!&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;ux:&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 0); font-family: Dotum, 돋움;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;button1&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;Clicked=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;{myTakePicture}&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;/Info&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;BackgroundImage File=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 255); font-family: Dotum, 돋움;&quot;&gt;&quot;{myfilePath}&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;/Page&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;lt;/DockPanel&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;line-height: 1; background: rgb(245, 245, 245);&quot;&gt;&lt;div style=&quot;font-stretch: normal; line-height: 1.6; margin: 0px; padding: 0px; vertical-align: top; border-left-width: 2px; border-left-style: solid; border-left-color: rgb(255, 255, 255);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&amp;lt;/App&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/ol&gt;&lt;p style=&quot;margin-left: 2em; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 0px; line-height: 1;&quot;&gt;&lt;span style=&quot;line-height: 1.5; font-family: Dotum, 돋움;&quot;&gt;(3) 테스트&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 0px; line-height: 1;&quot;&gt;&lt;span style=&quot;line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;line-height: 1.5;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;초기화면&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 359px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/214F943B563ABA9707&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F214F943B563ABA9707&quot; width=&quot;359&quot; height=&quot;611&quot; filename=&quot;1.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;촬영 후 화면&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;사진 아래에 파일 경로가 출력된 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 359px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/22491F3B563ABA9A01&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F22491F3B563ABA9A01&quot; width=&quot;359&quot; height=&quot;638&quot; filename=&quot;mail.worksmobile.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 80px; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;파일 저장 경로 확인&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;Android &amp;gt; data &amp;gt; 앱이름 &amp;gt; files 에 이미지가 저장 된 것을 확인할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 359px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/22379A3B563ABA9902&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F22379A3B563ABA9902&quot; width=&quot;359&quot; height=&quot;638&quot; filename=&quot;22.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 0px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-size: 14pt; color: rgb(0, 0, 0); font-family: Dotum, 돋움;&quot;&gt;&lt;b&gt;4. 정리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 0px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;카메라 호출 속도가 기존의 하이브리드 앱 툴에 비해 눈에 띄게 빨라서 놀랐다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;베타 환경이라는 점을 고려하면, 앞으로 하이브리드 앱을 개발하는데 있어서 점유율이 올라갈 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;아직 Native filesystem 을 이용할 수 있는 API 가 부족하여 촬영한 이미지를 갤러리 폴더로 옮기지 못했지만&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;기본이 되는 기능이므로 Fuse tools 에서 빠른 시일 내에, 업데이트할 것으로 예상한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;line-height: 1.5; font-family: Dotum, 돋움;&quot;&gt;이미지를 활용한 앱을 개발하기 위해서는 당분간 촬영한 이미지를 서버에 저장 가공 후, 제공해주는 형태로&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;line-height: 1.5; font-family: Dotum, 돋움;&quot;&gt;개발을 진행하는 것이 좋겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;span style=&quot;color: rgb(154, 154, 154); font-family: Dotum, 돋움;&quot;&gt;※&lt;/span&gt;&lt;span style=&quot;color: rgb(154, 154, 154); font-family: Dotum, 돋움;&quot;&gt;작성 코드 중 개선할 부분이나, 틀린 부분 지적해주시면 감사히 반영하도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 0px; line-height: 1;&quot;&gt;&lt;span style=&quot;font-size: 14pt; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;&lt;b&gt;5. 참조&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 40px; line-height: 1;&quot;&gt;&lt;a target=&quot;_blank&quot; class=&quot;con_link&quot; href=&quot;https://www.fusetools.com/&quot;&gt;&lt;span style=&quot;font-family: Dotum, 돋움;&quot;&gt;https://www.fusetools.com/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;line-height: 1;&quot;&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>FUSE</category>
      <category>Fuse</category>
      <category>fusetools</category>
      <category>hybrid camera</category>
      <category>HybridApp</category>
      <category>퓨즈</category>
      <category>하이브리드앱</category>
      <author>김병규</author>
      <guid isPermaLink="true">https://bkim.tistory.com/1</guid>
      <comments>https://bkim.tistory.com/1#entry1comment</comments>
      <pubDate>Thu, 5 Nov 2015 10:38:01 +0900</pubDate>
    </item>
  </channel>
</rss>