<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>five weeks</title>
    <link>https://like-while.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 13 Jul 2026 07:52:01 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>five weeks</managingEditor>
    <image>
      <title>five weeks</title>
      <url>https://tistory1.daumcdn.net/tistory/5874142/attach/a9ba1b8f398749a1ae7d235a215d6a07</url>
      <link>https://like-while.tistory.com</link>
    </image>
    <item>
      <title>네이버 부스트캠프 10기 웹 모바일 베이직 후기</title>
      <link>https://like-while.tistory.com/72</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/43EZy/btsPe6vA4UM/dln16iOwkc6QJ3zNxOSyB1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/43EZy/btsPe6vA4UM/dln16iOwkc6QJ3zNxOSyB1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/43EZy/btsPe6vA4UM/dln16iOwkc6QJ3zNxOSyB1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F43EZy%2FbtsPe6vA4UM%2Fdln16iOwkc6QJ3zNxOSyB1%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;1640&quot; height=&quot;720&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;지원 배경&lt;/h2&gt;
&lt;p data-end=&quot;149&quot; data-start=&quot;41&quot; data-ke-size=&quot;size16&quot;&gt;회사의 경영이 악화되어 퇴사를 결정하게 되었고, 이후 진로를 다시 설계하면서 여러 가능성을 열어두고 있었습니다. 그중 하나가 평소 관심 있었던 부트캠프를 통해 실력을 더 키우는 것이었습니다.&lt;/p&gt;
&lt;p data-end=&quot;255&quot; data-start=&quot;151&quot; data-ke-size=&quot;size16&quot;&gt;사실 2023년에 삼성청년SW아카데미(SSAFY) 모바일반을 이수한 경험이 있었는데, 그 과정에 매우 만족했기 때문에, 다른 부트캠프에도 도전해 보고 싶다는 생각을 가지고 있었습니다.&lt;/p&gt;
&lt;p data-end=&quot;314&quot; data-start=&quot;257&quot; data-ke-size=&quot;size16&quot;&gt;마침 퇴사를 준비하던 시기에 네이버 부스트캠프 모집 공고를 보게 되었고, 자연스럽게 지원하게 되었습니다.&lt;/p&gt;
&lt;p data-end=&quot;314&quot; data-start=&quot;257&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;314&quot; data-start=&quot;257&quot; data-ke-size=&quot;size26&quot;&gt;지원서 작성&lt;/h2&gt;
&lt;p data-end=&quot;172&quot; data-start=&quot;29&quot; data-ke-size=&quot;size16&quot;&gt;지원서를 작성할 때 가장 중요하게 생각한 것은 진정성이었습니다.&lt;br /&gt;기업에 제출하는 자기소개서처럼 포장하거나 꾸미기보다는, 왜 이 부트캠프에 지원하게 되었는지, 어떤 마음으로 임하려 하는지를 솔직하게 적었습니다.&lt;/p&gt;
&lt;p data-end=&quot;172&quot; data-start=&quot;29&quot; data-ke-size=&quot;size16&quot;&gt;저 같은 경우에는 원래 안드로이드 개발을 주로 공부했었는데 웹 풀스택에 대한 흥미가 생겨서 해당 부분을 공부하고 싶은 마음을 그대로 적었습니다.&lt;/p&gt;
&lt;p data-end=&quot;172&quot; data-start=&quot;29&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;172&quot; data-start=&quot;29&quot; data-ke-size=&quot;size26&quot;&gt;문제 해결력 테스트 준비&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bV0qEb/btsPeJ8yJAL/RabkPJPBFitm1sY6qAjJM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bV0qEb/btsPeJ8yJAL/RabkPJPBFitm1sY6qAjJM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bV0qEb/btsPeJ8yJAL/RabkPJPBFitm1sY6qAjJM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbV0qEb%2FbtsPeJ8yJAL%2FRabkPJPBFitm1sY6qAjJM0%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;1146&quot; height=&quot;463&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;211&quot; data-start=&quot;40&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;211&quot; data-start=&quot;40&quot; data-ke-size=&quot;size16&quot;&gt;저는 Java와 Kotlin을 주로 사용해 왔기 때문에 JavaScript는 다소 낯선 언어였습니다. 하지만 베이직 과정은 웹 풀스택 개발에 필요한 기초 개념과 실습을 차근차근 익힐 수 있도록 잘 구성되어 있어서, 진행하면서 문제 해결력 테스트에 필요한 수준까지 자연스럽게 학습할 수 있었습니다. 따라서 전공자라면 JavaScript를 처음 접하더라도 웹 풀스택 과정에 큰 부담 없이 지원하셔도 괜찮을 것 같다는 생각이 들었습니다.&lt;/p&gt;
&lt;p data-end=&quot;294&quot; data-start=&quot;213&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;470&quot; data-start=&quot;296&quot; data-ke-size=&quot;size16&quot;&gt;또한 저는 퇴사 직후라 조금 지친 상태였고, 다른 분들처럼 미리 JavaScript를 공부하거나 문제해결력 테스트를 준비하진 못했습니다. 그럼에도 불구하고 베이직 과정의 과제들을 꾸준히 따라가다 보니 필요한 지식을 충분히 쌓을 수 있었고, 그 덕분에 문제 해결력 테스트도 무사히 통과할 수 있었습니다.&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;베이직(2주)의 학습 과정&lt;/h2&gt;
&lt;p data-end=&quot;309&quot; data-start=&quot;91&quot; data-ke-size=&quot;size16&quot;&gt;베이직 캠프는 약 2주간 진행되며, 매일 주어지는 미션을 수행하고, 그 결과로 코드와 Readme를 제출하는 방식으로 운영됩니다.&lt;br /&gt;이 과정은 기초 개념을 처음부터 알려주는 형태가 아니라, 목표가 주어지면 스스로 학습하고 해결해 나가는 구조로 진행됩니다.&lt;br /&gt;공부의 양이나 깊이도 정해진 기준이 있는 것이 아니라, 각자가 스스로 계획하고 실천하는 자율적인 방식입니다.&lt;/p&gt;
&lt;p data-end=&quot;529&quot; data-start=&quot;311&quot; data-ke-size=&quot;size16&quot;&gt;저는 이전에 SSAFY 모바일 과정을 수료한 경험이 있었는데, 그 과정은 강사님이 계시고 커리큘럼이 체계적으로 구성되어 있어서, 대학에서 배운 전공 지식을 빠르게 복습하는 데 큰 도움이 되었습니다.&lt;br /&gt;그에 비해 베이직은 스스로 목표를 설정하고 주도적으로 학습하는 스타일이었고, 두 과정은 학습 방식이 매우 다르면서도 각자의 장점이 뚜렷해 서로 보완되는 경험이었습니다.&lt;/p&gt;
&lt;p data-end=&quot;529&quot; data-start=&quot;311&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;753&quot; data-start=&quot;531&quot; data-ke-size=&quot;size16&quot;&gt;또한, 리뷰를 위해 다른 수강생들의 결과물을 꼭 확인해야 하는 구조입니다.&lt;br /&gt;처음에는 뛰어난 분들이 많아 자연스럽게 비교하게 되지만, 리뷰 과정 자체가 하나의 학습 과정이라고 생각합니다.&lt;br /&gt;많은 input 없이 좋은 output을 만들어낼 수는 없다고 생각하기 때문에, 저는 좋은 코드나 구현 방식이 보이면 따로 메모해 두었다가 제 과제에 적용해 보았습니다.&lt;/p&gt;
&lt;p data-end=&quot;862&quot; data-start=&quot;755&quot; data-ke-size=&quot;size16&quot;&gt;특히 저는 JavaScript에 익숙하지 않았던 터라, 이 과정을 통해 JS 문법과 활용에 대해 실질적으로 많이 익힐 수 있었고, 짧은 시간 안에 언어에 대한 감을 익힐 수 있었습니다.&lt;/p&gt;
&lt;p data-end=&quot;286&quot; data-start=&quot;200&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;286&quot; data-start=&quot;200&quot; data-ke-size=&quot;size26&quot;&gt;학습 방법 팁&lt;/h2&gt;
&lt;p data-pm-slice=&quot;0 0 []&quot; data-ke-size=&quot;size16&quot;&gt;아래는 제가 베이직 과정을 진행하며 느낀 학습 팁들입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 완벽히 지킨 것은 아니지만, 지킨다면 확실히 도움이 될 만한 방법이라 생각되어 정리해 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 그날 과제는 그날 하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과제를 미루기 시작하면, 나중에는 시간에 쫓겨 제대로 학습하기 어려워집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 주어진 과제를 그날그날 수행하면, 하나의 주제에 더 깊이 몰입할 수 있고, 지속적인 리듬을 유지할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 다른 사람 코드 많이 보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 사람의 코드를 읽는 만큼 성장할 수 있다는 걸 절실히 느꼈습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 코드만 보지 말고, 다양한 방식의 접근과 구현을 보며 아이디어를 얻고, 그중 좋은 부분은 내 방식으로 소화해보는 연습이 중요합니다.&lt;/p&gt;
&lt;p data-end=&quot;341&quot; data-start=&quot;122&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;341&quot; data-start=&quot;122&quot; data-ke-size=&quot;size26&quot;&gt;베이직 과정에서 배운 점&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1405&quot; data-origin-height=&quot;819&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oLa6t/btsPfdBzKvH/ASd7E0DLu6rrZmYBapWFxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oLa6t/btsPfdBzKvH/ASd7E0DLu6rrZmYBapWFxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oLa6t/btsPfdBzKvH/ASd7E0DLu6rrZmYBapWFxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoLa6t%2FbtsPfdBzKvH%2FASd7E0DLu6rrZmYBapWFxk%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;1405&quot; height=&quot;819&quot; data-origin-width=&quot;1405&quot; data-origin-height=&quot;819&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;341&quot; data-start=&quot;122&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;341&quot; data-start=&quot;122&quot; data-ke-size=&quot;size16&quot;&gt;무언가를 처음 시작할 때는 못하는 게 당연하다고 생각합니다. 예를 들어 Kotlin으로는 어느 정도 익숙하게 구현할 수 있지만, JavaScript는 처음이라 어렵게 느껴졌습니다. 이처럼 익숙하지 않은 언어나 환경에서 어려움을 겪는 건 자연스러운 일이고, 못한다는 사실을 받아들이고, 그 상태를 견디는 과정이 결국 잘하게 되는 길이라고 믿습니다. 중요한 것은 포기하지 않고 요구사항을 끝까지 구현하려는 자세, 그리고 그 과정을 통해 배우고 익히려는 태도라는 사실을 다시 알 수 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;341&quot; data-start=&quot;122&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;341&quot; data-start=&quot;122&quot; data-ke-size=&quot;size16&quot;&gt;베이직에서 어떤점을 배우는지 잘 모르고 시작하게 되어 베이직 학습 목표를 적는 칸에 웹 풀스택에 대한 학습이라고 적어뒀었습니다. 하지만 해당 관련 과제는 아니었습니다. 베이직은 CS 관련 과제가 나오고 해당 부분을 구현하면서 학습하는 내용이었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb5OCp/btsPerAxvIV/BC41zvlNvGjaDIXOUNdyq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb5OCp/btsPerAxvIV/BC41zvlNvGjaDIXOUNdyq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb5OCp/btsPerAxvIV/BC41zvlNvGjaDIXOUNdyq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb5OCp%2FbtsPerAxvIV%2FBC41zvlNvGjaDIXOUNdyq1%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;1117&quot; height=&quot;502&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;341&quot; data-start=&quot;122&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;341&quot; data-start=&quot;122&quot; data-ke-size=&quot;size16&quot;&gt;회사를 다니면서 지쳐서 중간에 포기할 줄 알았는데 열심히 하는 분들이 많아서 저도 영향을 받아 덩달아 열심히 한 것 같습니다. 챌린지 과정도 성실하게 할 수 있도록 노력하겠습니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>기록&amp;amp;후기</category>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/72</guid>
      <comments>https://like-while.tistory.com/72#entry72comment</comments>
      <pubDate>Fri, 11 Jul 2025 13:24:52 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스(Database) 개념 정리</title>
      <link>https://like-while.tistory.com/71</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1xTyC/btsOh9BaNY8/G3fLrK4umQHowUuL0Icbzk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1xTyC/btsOh9BaNY8/G3fLrK4umQHowUuL0Icbzk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1xTyC/btsOh9BaNY8/G3fLrK4umQHowUuL0Icbzk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1xTyC%2FbtsOh9BaNY8%2FG3fLrK4umQHowUuL0Icbzk%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;1920&quot; height=&quot;1080&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;h2 id=&quot;2018cf77-bc66-8064-aaaf-c0f2ec03b86f&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. 데이터베이스란?&lt;/h2&gt;
&lt;p id=&quot;2018cf77-bc66-8068-81d1-ddf65f35d130&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여러 사람들이 다양한 방식으로 데이터를 저장, 검색, 수정할 수 있도록 구조화된 데이터의 집합&lt;br /&gt;앱 또는 시스템에서 데이터를 구조화하고 효율적으로 다루기 위한 도구&lt;/p&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-8068-8ad0-e9b7f0c39a48&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;사용 예시&lt;/b&gt;&lt;/p&gt;
&lt;ul id=&quot;2018cf77-bc66-8056-a246-e34a1e2e99cd&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;사용자 로그인 정보 저장 (이메일/비밀번호)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-802b-a87a-f44b1bcfb1e0&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;최근 사용 내역 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-80d9-9db0-f75bc33e2b35&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;오프라인 상태에서도 앱 작동 (ex. 메모 앱, 캘린더)&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;2018cf77-bc66-8027-83e9-e83c25abd27e&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-8064-aaaf-c0f2ec03b86f&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. DBMS (Database Management System)&lt;/h2&gt;
&lt;p id=&quot;2018cf77-bc66-80d5-bd35-e1ad3462a12c&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터베이스를 쉽게 사용할 수 있도록 해주는 소프트웨어&lt;/p&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-8087-bd4e-c11314ceb04d&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주요 역할&lt;/b&gt;&lt;/p&gt;
&lt;ul id=&quot;2018cf77-bc66-800e-9534-e8dbca6b6f9a&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;데이터를 파일이 아닌 논리적으로 관리 (인덱스, 트랜잭션, 동시성 제어 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-80e5-8e9b-decc57c3326f&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;SQL을 통해 데이터 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;2018cf77-bc66-807b-8433-fdda395ef766&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;대표 DBMS&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-8086-b57a-e4e2a32e45f6&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-8071-96e9-d2a24ce2ab01&quot;&gt;
&lt;td id=&quot;^J\F&quot; style=&quot;text-align: left;&quot;&gt;분류&lt;/td&gt;
&lt;td id=&quot;bDdL&quot; style=&quot;text-align: left;&quot;&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8090-ae37-d4654f2b87cc&quot;&gt;
&lt;td id=&quot;^J\F&quot; style=&quot;text-align: left;&quot;&gt;관계형 (RDB)&lt;/td&gt;
&lt;td id=&quot;bDdL&quot; style=&quot;text-align: left;&quot;&gt;MySQL, PostgreSQL, Oracle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-802c-9a62-eccbd99170f6&quot;&gt;
&lt;td id=&quot;^J\F&quot; style=&quot;text-align: left;&quot;&gt;비관계형 (NoSQL)&lt;/td&gt;
&lt;td id=&quot;bDdL&quot; style=&quot;text-align: left;&quot;&gt;MongoDB, Firebase, Redis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-807c-aa12-dfbc0e7dc56d&quot;&gt;
&lt;td id=&quot;^J\F&quot; style=&quot;text-align: left;&quot;&gt;로컬 DB&lt;/td&gt;
&lt;td id=&quot;bDdL&quot; style=&quot;text-align: left;&quot;&gt;SQLite, Room&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p id=&quot;2018cf77-bc66-8030-9d16-f6babd93a58b&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-8079-bbdc-cc7aab3071b7&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. SQL (Structured Query Language)&lt;/h2&gt;
&lt;p id=&quot;2018cf77-bc66-805c-a1c4-cb6a30f21415&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터베이스에 명령을 내리는 표준 언어&lt;/p&gt;
&lt;pre id=&quot;2018cf77-bc66-804d-a2e2-f79ba57f4474&quot; class=&quot;routeros&quot; style=&quot;background-color: #f5f2f0; color: #000000; text-align: left;&quot;&gt;&lt;code&gt;SELECT * FROM users WHERE age &amp;gt; 20;
INSERT INTO users (name, age) VALUES ('Anna', 25);
UPDATE users SET age = 26 WHERE name = 'Anna';
DELETE FROM users WHERE age &amp;lt; 18;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;연산 종류&lt;/b&gt;&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-8050-9c2c-d9a765c86a69&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-804b-a58f-e37029f8eaa1&quot;&gt;
&lt;td id=&quot;tyx]&quot; style=&quot;text-align: left;&quot;&gt;연산&lt;/td&gt;
&lt;td id=&quot;ZFit&quot; style=&quot;text-align: left;&quot;&gt;주의할 점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80c5-89ba-d00fc83d97e4&quot;&gt;
&lt;td id=&quot;tyx]&quot; style=&quot;text-align: left;&quot;&gt;SELECT (조회)&lt;/td&gt;
&lt;td id=&quot;ZFit&quot; style=&quot;text-align: left;&quot;&gt;인덱스가 없으면 느려짐 &amp;rarr; WHERE 조건에 인덱싱 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8069-88c2-fd050f67eef5&quot;&gt;
&lt;td id=&quot;tyx]&quot; style=&quot;text-align: left;&quot;&gt;INSERT (삽입)&lt;/td&gt;
&lt;td id=&quot;ZFit&quot; style=&quot;text-align: left;&quot;&gt;UNIQUE 제약조건 충돌 주의. 대량 삽입 시 배치 처리 고려&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8027-8884-f3fef53b51be&quot;&gt;
&lt;td id=&quot;tyx]&quot; style=&quot;text-align: left;&quot;&gt;UPDATE (수정)&lt;/td&gt;
&lt;td id=&quot;ZFit&quot; style=&quot;text-align: left;&quot;&gt;WHERE 누락 시 전체 수정됨 &amp;rarr; 항상 조건문 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8053-b3c5-f2b1714ec27c&quot;&gt;
&lt;td id=&quot;tyx]&quot; style=&quot;text-align: left;&quot;&gt;DELETE (삭제)&lt;/td&gt;
&lt;td id=&quot;ZFit&quot; style=&quot;text-align: left;&quot;&gt;트랜잭션 사용 필수. 외래키 제약이 있다면 제약 해제 순서 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;2018cf77-bc66-80ad-95ae-d38481e16a57&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;4. 관계형 데이터베이스 (RDB: Relational Database)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-80ee-b49c-f8591deca783&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;핵심 개념&lt;/b&gt;&lt;/p&gt;
&lt;ul id=&quot;2018cf77-bc66-8049-9b8b-f05c8c8598e8&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;데이터를 테이블 단위로 저장 (엑셀처럼 행과 열)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-8046-b5b4-e665ba9aa26c&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;테이블 간 관계 설정 가능 (Join)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-807c-a5a6-f1d731150be8&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;JOIN이 많아질수록 성능 이슈 발생 가능 &amp;rarr; 인덱스 튜닝 필수&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-80fe-9822-f15f8cce9324&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;엄격한 스키마 구조 &amp;rarr; 데이터 간 관계가 명확한 경우 추천&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-805d-9697-c1c60bd0b7a3&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;트랜잭션 처리로 데이터 정합성을 보장할 수 있어 업무 로직에 신뢰성 요구될 때 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;2018cf77-bc66-8089-a632-dcaa6752d89b&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주요 용어&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-80c7-bb15-fa0f2daed7e4&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-805e-934d-d15a1a180208&quot;&gt;
&lt;td id=&quot;==ke&quot; style=&quot;text-align: left;&quot;&gt;용어&lt;/td&gt;
&lt;td id=&quot;&amp;gt;&amp;gt;ZU&quot; style=&quot;text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8076-8008-e60d0cdf3d9a&quot;&gt;
&lt;td id=&quot;==ke&quot; style=&quot;text-align: left;&quot;&gt;테이블&lt;/td&gt;
&lt;td id=&quot;&amp;gt;&amp;gt;ZU&quot; style=&quot;text-align: left;&quot;&gt;데이터 저장 단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-804a-bbaa-f025a7870903&quot;&gt;
&lt;td id=&quot;==ke&quot; style=&quot;text-align: left;&quot;&gt;행(Row)&lt;/td&gt;
&lt;td id=&quot;&amp;gt;&amp;gt;ZU&quot; style=&quot;text-align: left;&quot;&gt;레코드, 데이터 한 건&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8043-9b11-c8239a5e829e&quot;&gt;
&lt;td id=&quot;==ke&quot; style=&quot;text-align: left;&quot;&gt;열(Column)&lt;/td&gt;
&lt;td id=&quot;&amp;gt;&amp;gt;ZU&quot; style=&quot;text-align: left;&quot;&gt;속성 (이름, 나이 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-804f-bdba-f7f3a26e9869&quot;&gt;
&lt;td id=&quot;==ke&quot; style=&quot;text-align: left;&quot;&gt;기본키(PK)&lt;/td&gt;
&lt;td id=&quot;&amp;gt;&amp;gt;ZU&quot; style=&quot;text-align: left;&quot;&gt;각 행을 유일하게 식별&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8083-b74e-eef853fab1ab&quot;&gt;
&lt;td id=&quot;==ke&quot; style=&quot;text-align: left;&quot;&gt;외래키(FK)&lt;/td&gt;
&lt;td id=&quot;&amp;gt;&amp;gt;ZU&quot; style=&quot;text-align: left;&quot;&gt;다른 테이블과의 관계를 나타냄&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80bf-89a4-fe3169ddd5be&quot;&gt;
&lt;td id=&quot;==ke&quot; style=&quot;text-align: left;&quot;&gt;스키마&lt;/td&gt;
&lt;td id=&quot;&amp;gt;&amp;gt;ZU&quot; style=&quot;text-align: left;&quot;&gt;테이블 구조 정의&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;2018cf77-bc66-80f0-a8fd-ece12f1b520e&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;5. 키(Key)의 종류&lt;/h2&gt;
&lt;table id=&quot;2018cf77-bc66-8060-bbd4-f2152e7d5fbd&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-806c-95ca-d5d6575be0af&quot;&gt;
&lt;td id=&quot;ilpV&quot; style=&quot;text-align: left;&quot;&gt;키 종류&lt;/td&gt;
&lt;td id=&quot;MdXR&quot; style=&quot;text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8066-9b6f-cf55d1cb25fb&quot;&gt;
&lt;td id=&quot;ilpV&quot; style=&quot;text-align: left;&quot;&gt;슈퍼 키(Super Key)&lt;/td&gt;
&lt;td id=&quot;MdXR&quot; style=&quot;text-align: left;&quot;&gt;유일성만 만족&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8034-9785-d2d455ea97b6&quot;&gt;
&lt;td id=&quot;ilpV&quot; style=&quot;text-align: left;&quot;&gt;후보 키(Candidate Key)&lt;/td&gt;
&lt;td id=&quot;MdXR&quot; style=&quot;text-align: left;&quot;&gt;슈퍼 키 중 최소성도 만족&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-808c-95ae-ffce63dfaad5&quot;&gt;
&lt;td id=&quot;ilpV&quot; style=&quot;text-align: left;&quot;&gt;기본 키(Primary Key)&lt;/td&gt;
&lt;td id=&quot;MdXR&quot; style=&quot;text-align: left;&quot;&gt;후보 키 중 하나 선택 (NOT NULL + UNIQUE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80a7-9c4a-c81053486640&quot;&gt;
&lt;td id=&quot;ilpV&quot; style=&quot;text-align: left;&quot;&gt;대체 키(Alternate Key)&lt;/td&gt;
&lt;td id=&quot;MdXR&quot; style=&quot;text-align: left;&quot;&gt;후보 키 중 기본 키 제외한 나머지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80e4-aec7-ed0ae90e229c&quot;&gt;
&lt;td id=&quot;ilpV&quot; style=&quot;text-align: left;&quot;&gt;외래 키(Foreign Key)&lt;/td&gt;
&lt;td id=&quot;MdXR&quot; style=&quot;text-align: left;&quot;&gt;다른 테이블의 기본 키를 참조&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;2018cf77-bc66-8060-b7a9-e23283c0f65a&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;6. 정규화(Normalization)&lt;/h2&gt;
&lt;ul id=&quot;2018cf77-bc66-80e6-9a66-c2b50eff1de5&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;중복 제거 및 데이터 무결성을 위해 테이블을 구조적으로 나누는 과정&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-806f-818f-fc3e62815861&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;정규화는 중복 제거와 무결성 확보에 효과적&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-80aa-9201-e5c3817cd526&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;하지만 과도한 정규화 &amp;rarr; JOIN 남발 &amp;rarr; 성능 저하&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-8010-b1f3-f49496191b7d&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;실무에서는 3NF 또는 BCNF까지만 적용하고, 필요한 경우 비정규화로 속도 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;table id=&quot;2018cf77-bc66-80cc-8264-c3c59a086305&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-80b6-b09d-da5bfc50f3cb&quot;&gt;
&lt;td id=&quot;qaUZ&quot; style=&quot;text-align: left;&quot;&gt;정규형&lt;/td&gt;
&lt;td id=&quot;w~iV&quot; style=&quot;text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80d8-8558-e9faae32fd38&quot;&gt;
&lt;td id=&quot;qaUZ&quot; style=&quot;text-align: left;&quot;&gt;제1정규형 (1NF)&lt;/td&gt;
&lt;td id=&quot;w~iV&quot; style=&quot;text-align: left;&quot;&gt;컬럼이 원자값(단일값)만 가지도록 분리 (중첩/반복되는 컬럼 제거)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-806c-81bf-e3a2df5fc265&quot;&gt;
&lt;td id=&quot;qaUZ&quot; style=&quot;text-align: left;&quot;&gt;제2정규형 (2NF)&lt;/td&gt;
&lt;td id=&quot;w~iV&quot; style=&quot;text-align: left;&quot;&gt;제1정규형 만족 + 기본키의 일부에만 종속된 컬럼 제거 (부분 종속 제거)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8018-a7fc-f0e7699e6ae5&quot;&gt;
&lt;td id=&quot;qaUZ&quot; style=&quot;text-align: left;&quot;&gt;제3정규형 (3NF)&lt;/td&gt;
&lt;td id=&quot;w~iV&quot; style=&quot;text-align: left;&quot;&gt;제2정규형 만족 + 이행적 종속 제거 (비기본키 &amp;rarr; 다른 비기본키 종속 제거)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-803c-bb0e-d18212f4c609&quot;&gt;
&lt;td id=&quot;qaUZ&quot; style=&quot;text-align: left;&quot;&gt;BCNF (보이스-코드 정규형)&lt;/td&gt;
&lt;td id=&quot;w~iV&quot; style=&quot;text-align: left;&quot;&gt;제3정규형 만족 + 모든 결정자가 후보키일 것 (후보키 아닌 컬럼이 결정자면 분해)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80bc-83df-e6692b55416b&quot;&gt;
&lt;td id=&quot;qaUZ&quot; style=&quot;text-align: left;&quot;&gt;제4정규형 (4NF)&lt;/td&gt;
&lt;td id=&quot;w~iV&quot; style=&quot;text-align: left;&quot;&gt;BCNF 만족 + 다치 종속 제거 (하나의 키가 여러 독립적인 다중값을 가질 때 분리)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80e2-8602-e8d2729c2cf4&quot;&gt;
&lt;td id=&quot;qaUZ&quot; style=&quot;text-align: left;&quot;&gt;제5정규형 (5NF)&lt;/td&gt;
&lt;td id=&quot;w~iV&quot; style=&quot;text-align: left;&quot;&gt;제4정규형 만족 + 조인 종속 제거 (조인 후에도 정보 손실 없이 복원 가능하게 분해)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-8053-9039-d977b531c999&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;용어 정리&lt;/b&gt;&lt;/p&gt;
&lt;ul id=&quot;2018cf77-bc66-80e3-9b95-e8f9677a359c&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;부분 종속: 기본키의 일부에만 종속됨&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-8076-b492-f15fd3e51dfd&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;이행적 종속: A &amp;rarr; B, B &amp;rarr; C이면 A &amp;rarr; C가 되는 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-8019-be07-eb75990b2885&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;결정자: 다른 값을 결정하는 컬럼 (예: 학번 &amp;rarr; 이름)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-80a1-8d4f-e56ebc325977&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;다치 종속: 하나의 속성이 여러 개의 독립된 값을 가짐&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-8000-b486-dc9739957602&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;조인 종속: 테이블을 조인했을 때만 의미가 있는 종속 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;2018cf77-bc66-803d-a71b-fc733b0facf6&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-80b2-a78c-cce2400434b1&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;7. 트랜잭션과 ACID&lt;/h2&gt;
&lt;p id=&quot;2018cf77-bc66-80ab-8c6c-e1be0429549f&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;트랜잭션: 데이터베이스 작업의 논리적 단위&lt;/p&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-8092-889b-ed05d77141d0&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ACID 4원칙&lt;/b&gt;&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-8077-afbe-e066939586af&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-8069-bef2-dcb78d731cb0&quot;&gt;
&lt;td id=&quot;FMWi&quot; style=&quot;text-align: left;&quot;&gt;항목&lt;/td&gt;
&lt;td id=&quot;su{]&quot; style=&quot;text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-803d-b884-c53242021987&quot;&gt;
&lt;td id=&quot;FMWi&quot; style=&quot;text-align: left;&quot;&gt;원자성(Atomicity)&lt;/td&gt;
&lt;td id=&quot;su{]&quot; style=&quot;text-align: left;&quot;&gt;전부 실행되거나 전부 취소됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8008-b795-f4e1d2de24d6&quot;&gt;
&lt;td id=&quot;FMWi&quot; style=&quot;text-align: left;&quot;&gt;일관성(Consistency)&lt;/td&gt;
&lt;td id=&quot;su{]&quot; style=&quot;text-align: left;&quot;&gt;무결한 상태 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80b4-afe9-eeb7331535f1&quot;&gt;
&lt;td id=&quot;FMWi&quot; style=&quot;text-align: left;&quot;&gt;고립성(Isolation)&lt;/td&gt;
&lt;td id=&quot;su{]&quot; style=&quot;text-align: left;&quot;&gt;동시에 실행돼도 서로 영향 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80ae-90aa-dd80f8bb61d4&quot;&gt;
&lt;td id=&quot;FMWi&quot; style=&quot;text-align: left;&quot;&gt;지속성(Durability)&lt;/td&gt;
&lt;td id=&quot;su{]&quot; style=&quot;text-align: left;&quot;&gt;커밋된 내용은 영구 저장됨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p id=&quot;2018cf77-bc66-8001-b916-f7f9125c418f&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-801c-9ab3-cbcdd6208624&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;8. 인덱스(Index)&lt;/h2&gt;
&lt;p id=&quot;2018cf77-bc66-8004-bcb8-cde0a48d0e61&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터를 빠르게 찾기 위한 자료 구조 (책의 목차 역할)&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-8045-90b5-c990b109d681&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-808f-afef-f47fc890e036&quot;&gt;
&lt;td id=&quot;::MU&quot; style=&quot;text-align: left;&quot;&gt;항목&lt;/td&gt;
&lt;td id=&quot;eIHa&quot; style=&quot;text-align: left;&quot;&gt;실무 팁&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80c5-998a-fba1bae8f32e&quot;&gt;
&lt;td id=&quot;::MU&quot; style=&quot;text-align: left;&quot;&gt;WHERE 조건&lt;/td&gt;
&lt;td id=&quot;eIHa&quot; style=&quot;text-align: left;&quot;&gt;자주 사용하는 컬럼에 인덱스 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80c4-909c-cc936caa0d0e&quot;&gt;
&lt;td id=&quot;::MU&quot; style=&quot;text-align: left;&quot;&gt;정렬(SORT)&lt;/td&gt;
&lt;td id=&quot;eIHa&quot; style=&quot;text-align: left;&quot;&gt;ORDER BY 대상에도 인덱스 고려&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8040-8de2-dd88fce7a633&quot;&gt;
&lt;td id=&quot;::MU&quot; style=&quot;text-align: left;&quot;&gt;JOIN&lt;/td&gt;
&lt;td id=&quot;eIHa&quot; style=&quot;text-align: left;&quot;&gt;조인 대상 컬럼 인덱스 필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-805b-b89c-d8b018d6376d&quot;&gt;
&lt;td id=&quot;::MU&quot; style=&quot;text-align: left;&quot;&gt;INSERT/UPDATE&lt;/td&gt;
&lt;td id=&quot;eIHa&quot; style=&quot;text-align: left;&quot;&gt;인덱스 많을수록 느려짐 &amp;rarr; 쓰기 빈번한 테이블은 인덱스 최소화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-804f-9353-f844ed352282&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ul id=&quot;2018cf77-bc66-806c-ab73-ec416a4fa21a&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;검색 속도 향상&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-8076-a7df-e3573ced2434&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;정렬 빠름&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-804a-a40a-d154477268fc&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;유니크 제약 조건으로 데이터 무결성 강화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-804f-a62e-fe8e76335a7e&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul id=&quot;2018cf77-bc66-80c9-9a95-f75a69ce359e&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;인덱스 생성/유지 비용&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-8037-9e0d-dadf45955de1&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;INSERT/UPDATE 성능 저하&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;2018cf77-bc66-8011-93f6-efd61792c07c&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-804e-b4b7-e8ea4e3d48aa&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;9. 이상 현상(Anomaly)&lt;/h2&gt;
&lt;p id=&quot;2018cf77-bc66-806a-9a9c-e542e34856d1&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;테이블 구조가 비정상적일 때 생기는 문제&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-800a-8127-f0089d92a231&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-8094-800f-e4121c49f815&quot;&gt;
&lt;td id=&quot;Nz&amp;#96;M&quot; style=&quot;text-align: left;&quot;&gt;유형&lt;/td&gt;
&lt;td id=&quot;|Pyk&quot; style=&quot;text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8079-8129-f9449ab3097d&quot;&gt;
&lt;td id=&quot;Nz&amp;#96;M&quot; style=&quot;text-align: left;&quot;&gt;삽입 이상&lt;/td&gt;
&lt;td id=&quot;|Pyk&quot; style=&quot;text-align: left;&quot;&gt;일부 정보 없으면 삽입 안 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8050-b2db-d82260bcc7c2&quot;&gt;
&lt;td id=&quot;Nz&amp;#96;M&quot; style=&quot;text-align: left;&quot;&gt;삭제 이상&lt;/td&gt;
&lt;td id=&quot;|Pyk&quot; style=&quot;text-align: left;&quot;&gt;하나 지우면 관련 정보도 삭제됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-802f-9f7f-ebdccac359a9&quot;&gt;
&lt;td id=&quot;Nz&amp;#96;M&quot; style=&quot;text-align: left;&quot;&gt;갱신 이상&lt;/td&gt;
&lt;td id=&quot;|Pyk&quot; style=&quot;text-align: left;&quot;&gt;일부만 수정돼 정보 모순 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p id=&quot;2018cf77-bc66-805f-89cf-dee04234325a&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-8060-9278-ced538e7be6b&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;10. ERD (Entity Relationship Diagram)&lt;/h2&gt;
&lt;p id=&quot;2018cf77-bc66-80d2-ad1d-d1b50f30ea95&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;시스템에서 사용하는 개체(엔티티)와 그 관계를 도식화한 데이터베이스 설계도&lt;/p&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-808e-b2df-c124d468ec2e&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주요 개념&lt;/b&gt;&lt;/p&gt;
&lt;ul id=&quot;2018cf77-bc66-80ef-887c-c01376ceaaf5&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;엔티티(Entity): 테이블에 대응 (예: User)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-8008-8c10-edd5a3fd1f89&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;속성(Attribute): 테이블의 열&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-80a6-b162-d6b1ef068a20&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;관계(Relationship): 엔티티 간의 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-80c5-a2dd-da4d68bb8aad&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;관계 유형&lt;/b&gt;&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-8047-86c6-dbe5cdf9aa0b&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-8077-9e41-dc857e475429&quot;&gt;
&lt;td id=&quot;Ofk@&quot; style=&quot;text-align: left;&quot;&gt;기준&lt;/td&gt;
&lt;td id=&quot;rMQD&quot; style=&quot;text-align: left;&quot;&gt;관계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-801f-ae8d-d7b927209472&quot;&gt;
&lt;td id=&quot;Ofk@&quot; style=&quot;text-align: left;&quot;&gt;외래 키 위치&lt;/td&gt;
&lt;td id=&quot;rMQD&quot; style=&quot;text-align: left;&quot;&gt;식별자 관계 vs 비식별자 관계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80db-8cab-e06c642465b1&quot;&gt;
&lt;td id=&quot;Ofk@&quot; style=&quot;text-align: left;&quot;&gt;발생 횟수&lt;/td&gt;
&lt;td id=&quot;rMQD&quot; style=&quot;text-align: left;&quot;&gt;1:1, 1:N, N:N&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p id=&quot;2018cf77-bc66-80f1-84ed-d350aa6efbb7&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-80b0-831a-ef061b561699&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;11. NoSQL (Not Only SQL, 비관계형 데이터베이스)&lt;/h2&gt;
&lt;p id=&quot;2018cf77-bc66-809c-b964-da5820c44e04&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유연한 구조, 대규모 확장을 위해 등장한 비관계형 데이터베이스&lt;/p&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-8023-bd35-eac546b08523&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;등장 배경&lt;/b&gt;&lt;/p&gt;
&lt;ul id=&quot;2018cf77-bc66-802c-89ad-cbab23a2f55e&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;스키마 변경 어려움, JOIN 많은 관계형 DB의 한계&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-803f-b7a1-cc3456551751&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;트래픽 많고 유연성 필요한 서비스 (SNS, IoT 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-802f-a679-c9995fb3296f&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;사용 조건&lt;/b&gt;&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-80b7-8ec3-e523ed695a34&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-80d4-93b5-eb9ddec5d862&quot;&gt;
&lt;td id=&quot;dfDW&quot; style=&quot;text-align: left;&quot;&gt;사용 조건&lt;/td&gt;
&lt;td id=&quot;_]:_&quot; style=&quot;text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80a8-b6cc-e35c88348685&quot;&gt;
&lt;td id=&quot;dfDW&quot; style=&quot;text-align: left;&quot;&gt;스키마 자주 변경됨&lt;/td&gt;
&lt;td id=&quot;_]:_&quot; style=&quot;text-align: left;&quot;&gt;문서 기반(JSON)은 구조 자유로움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8093-a9c2-fa21328f5ddc&quot;&gt;
&lt;td id=&quot;dfDW&quot; style=&quot;text-align: left;&quot;&gt;수평 확장 필요&lt;/td&gt;
&lt;td id=&quot;_]:_&quot; style=&quot;text-align: left;&quot;&gt;서버 수 늘리기 쉬움 (샤딩 지원)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80b6-be88-ecbc3a622d6d&quot;&gt;
&lt;td id=&quot;dfDW&quot; style=&quot;text-align: left;&quot;&gt;고속 읽기/쓰기&lt;/td&gt;
&lt;td id=&quot;_]:_&quot; style=&quot;text-align: left;&quot;&gt;단순 key-value 조회 성능 우수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80b5-9010-c38dcc9e93d0&quot;&gt;
&lt;td id=&quot;dfDW&quot; style=&quot;text-align: left;&quot;&gt;관계 표현이 불필요&lt;/td&gt;
&lt;td id=&quot;_]:_&quot; style=&quot;text-align: left;&quot;&gt;조인이 거의 필요 없는 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-807a-9a8f-c673adaa8059&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주요 유형&lt;/b&gt;&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-80a7-a28c-f40be24e3353&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-8009-9ef8-e3ad6e24ccaa&quot;&gt;
&lt;td id=&quot;=n_l&quot; style=&quot;text-align: left;&quot;&gt;유형&lt;/td&gt;
&lt;td id=&quot;unIg&quot; style=&quot;text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;td id=&quot;oVeO&quot; style=&quot;text-align: left;&quot;&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80ba-865e-fb04e45c14b5&quot;&gt;
&lt;td id=&quot;=n_l&quot; style=&quot;text-align: left;&quot;&gt;Document&lt;/td&gt;
&lt;td id=&quot;unIg&quot; style=&quot;text-align: left;&quot;&gt;JSON 문서 기반&lt;/td&gt;
&lt;td id=&quot;oVeO&quot; style=&quot;text-align: left;&quot;&gt;MongoDB, Firebase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80b2-8b0a-eee681017c46&quot;&gt;
&lt;td id=&quot;=n_l&quot; style=&quot;text-align: left;&quot;&gt;Key-Value&lt;/td&gt;
&lt;td id=&quot;unIg&quot; style=&quot;text-align: left;&quot;&gt;키-값 쌍&lt;/td&gt;
&lt;td id=&quot;oVeO&quot; style=&quot;text-align: left;&quot;&gt;Redis, DynamoDB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80da-9976-c9a65520e431&quot;&gt;
&lt;td id=&quot;=n_l&quot; style=&quot;text-align: left;&quot;&gt;Column&lt;/td&gt;
&lt;td id=&quot;unIg&quot; style=&quot;text-align: left;&quot;&gt;열 단위 저장&lt;/td&gt;
&lt;td id=&quot;oVeO&quot; style=&quot;text-align: left;&quot;&gt;Cassandra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-801c-84ed-ec017c743580&quot;&gt;
&lt;td id=&quot;=n_l&quot; style=&quot;text-align: left;&quot;&gt;Graph&lt;/td&gt;
&lt;td id=&quot;unIg&quot; style=&quot;text-align: left;&quot;&gt;노드-엣지 기반&lt;/td&gt;
&lt;td id=&quot;oVeO&quot; style=&quot;text-align: left;&quot;&gt;Neo4j&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p id=&quot;2018cf77-bc66-8092-ad60-fa4bf0579b68&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-8066-aec9-ee43a4462bdc&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;12. MongoDB 특징 (Document DB)&lt;/h2&gt;
&lt;ul id=&quot;2018cf77-bc66-8064-a2c8-d327675b860c&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;JSON 형태로 저장 (유연한 스키마)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-803c-894c-d9b4202ca160&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;Collection 단위로 관리 (테이블 개념)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-80d8-9240-d36f2d50741f&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;샤딩(Sharding), 복제(Replication), 트랜잭션 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;2018cf77-bc66-80f8-bb63-d993d8ee2707&quot; class=&quot;json&quot; style=&quot;background-color: #f5f2f0; color: #000000; text-align: left;&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;Anna&quot;,
  &quot;age&quot;: 25,
  &quot;tags&quot;: [&quot;developer&quot;, &quot;blogger&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;2018cf77-bc66-8076-bfa6-cf134ba24fe1&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-80ed-b626-c26e8cbe5c98&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;13. RDB vs NoSQL 선택 기준 요약&lt;/h2&gt;
&lt;table id=&quot;2018cf77-bc66-80b8-85f3-cde3d39c0556&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-80e5-bbf6-e791d2c1ec7d&quot;&gt;
&lt;td id=&quot;Cid@&quot; style=&quot;text-align: left;&quot;&gt;항목&lt;/td&gt;
&lt;td id=&quot;?Nji&quot; style=&quot;text-align: left;&quot;&gt;RDB&lt;/td&gt;
&lt;td id=&quot;kzkz&quot; style=&quot;text-align: left;&quot;&gt;NoSQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8015-8e94-ff3b9b682116&quot;&gt;
&lt;td id=&quot;Cid@&quot; style=&quot;text-align: left;&quot;&gt;구조&lt;/td&gt;
&lt;td id=&quot;?Nji&quot; style=&quot;text-align: left;&quot;&gt;테이블, 고정된 스키마&lt;/td&gt;
&lt;td id=&quot;kzkz&quot; style=&quot;text-align: left;&quot;&gt;JSON, 유연한 스키마&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80a5-9fa8-ca1d09d93712&quot;&gt;
&lt;td id=&quot;Cid@&quot; style=&quot;text-align: left;&quot;&gt;트랜잭션&lt;/td&gt;
&lt;td id=&quot;?Nji&quot; style=&quot;text-align: left;&quot;&gt;ACID 강력 지원&lt;/td&gt;
&lt;td id=&quot;kzkz&quot; style=&quot;text-align: left;&quot;&gt;약함 또는 제한적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8008-be56-d65010a70fb8&quot;&gt;
&lt;td id=&quot;Cid@&quot; style=&quot;text-align: left;&quot;&gt;JOIN&lt;/td&gt;
&lt;td id=&quot;?Nji&quot; style=&quot;text-align: left;&quot;&gt;가능&lt;/td&gt;
&lt;td id=&quot;kzkz&quot; style=&quot;text-align: left;&quot;&gt;불가 또는 복잡&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-80f7-a628-cce932113372&quot;&gt;
&lt;td id=&quot;Cid@&quot; style=&quot;text-align: left;&quot;&gt;확장성&lt;/td&gt;
&lt;td id=&quot;?Nji&quot; style=&quot;text-align: left;&quot;&gt;수직 확장&lt;/td&gt;
&lt;td id=&quot;kzkz&quot; style=&quot;text-align: left;&quot;&gt;수평 확장 유리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-802b-b9b2-d69923b5e1f3&quot;&gt;
&lt;td id=&quot;Cid@&quot; style=&quot;text-align: left;&quot;&gt;사용 예&lt;/td&gt;
&lt;td id=&quot;?Nji&quot; style=&quot;text-align: left;&quot;&gt;금융, ERP&lt;/td&gt;
&lt;td id=&quot;kzkz&quot; style=&quot;text-align: left;&quot;&gt;SNS, 로그, IoT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p id=&quot;2018cf77-bc66-80af-ab78-edeb378e6eca&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2018cf77-bc66-802e-87ca-dd15b2fe5140&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;14. 로컬 데이터베이스&lt;/h2&gt;
&lt;p id=&quot;2018cf77-bc66-80c4-b52d-c9f5e3165bd4&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;로컬 데이터베이스란 네트워크 없이도 디바이스 내부에 데이터를 저장하고 조회할 수 있는 데이터베이스를 의미합니다. 서버와 통신하지 않아도 사용할 수 있어 오프라인 환경에서도 작동 가능합니다.&lt;/p&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-80e5-a8d5-d275000fbca1&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;사용 조건&lt;/b&gt;&lt;/p&gt;
&lt;table id=&quot;2018cf77-bc66-8040-8042-fb0b552defba&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-8071-b073-f0c728f63ec4&quot;&gt;
&lt;td id=&quot;APwc&quot; style=&quot;text-align: left;&quot;&gt;상황&lt;/td&gt;
&lt;td id=&quot;|R[Q&quot; style=&quot;text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8055-905c-d6c1cd5a8b75&quot;&gt;
&lt;td id=&quot;APwc&quot; style=&quot;text-align: left;&quot;&gt;오프라인 데이터 저장&lt;/td&gt;
&lt;td id=&quot;|R[Q&quot; style=&quot;text-align: left;&quot;&gt;일정, 메모, 투두리스트, 기사 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8099-bcd9-c24715049e0c&quot;&gt;
&lt;td id=&quot;APwc&quot; style=&quot;text-align: left;&quot;&gt;서버와 주기적 동기화&lt;/td&gt;
&lt;td id=&quot;|R[Q&quot; style=&quot;text-align: left;&quot;&gt;서버 연동 전 임시 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8075-8869-e093fe451d24&quot;&gt;
&lt;td id=&quot;APwc&quot; style=&quot;text-align: left;&quot;&gt;빠른 UI 표시용 캐시&lt;/td&gt;
&lt;td id=&quot;|R[Q&quot; style=&quot;text-align: left;&quot;&gt;검색 결과, 최근 본 항목 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2018cf77-bc66-804b-ba95-c8a6a2c7de7e&quot; style=&quot;color: #37352f; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;ul id=&quot;2018cf77-bc66-8010-8d44-e6815c42d4b4&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;디바이스 내 저장: 스마트폰, 태블릿, PC 등의 내부 저장소에 위치&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-802a-a755-f39974c70b5d&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;빠른 접근 속도: 네트워크 지연 없이 즉시 데이터에 접근 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-80cb-9efd-e50d7d56b0c2&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;오프라인 지원: 인터넷 연결 없이도 데이터 조회/수정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&quot;2018cf77-bc66-8075-8f72-da8ed5916463&quot; style=&quot;list-style-type: disc; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;보안 이슈: 디바이스 분실 시 보안 문제 발생 가능 (암호화 필요)&lt;/li&gt;
&lt;/ul&gt;
&lt;table id=&quot;2018cf77-bc66-805e-9910-c85ed83c10ca&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;2018cf77-bc66-80d5-886e-d3549758c481&quot;&gt;
&lt;td id=&quot;RrVY&quot; style=&quot;text-align: left;&quot;&gt;플랫폼&lt;/td&gt;
&lt;td id=&quot;YRON&quot; style=&quot;text-align: left;&quot;&gt;로컬 데이터베이스 예시&lt;/td&gt;
&lt;td id=&quot;c&amp;gt;p=&quot; style=&quot;text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-800f-8be3-d661a7a3011f&quot;&gt;
&lt;td id=&quot;RrVY&quot; style=&quot;text-align: left;&quot;&gt;Android&lt;/td&gt;
&lt;td id=&quot;YRON&quot; style=&quot;text-align: left;&quot;&gt;SQLite, Room (SQLite 기반 ORM)&lt;/td&gt;
&lt;td id=&quot;c&amp;gt;p=&quot; style=&quot;text-align: left;&quot;&gt;안드로이드 기본 DB, Room은 SQLite를 추상화해 사용 편리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-804d-b00d-d19c53b3f7ae&quot;&gt;
&lt;td id=&quot;RrVY&quot; style=&quot;text-align: left;&quot;&gt;iOS&lt;/td&gt;
&lt;td id=&quot;YRON&quot; style=&quot;text-align: left;&quot;&gt;Core Data, SQLite&lt;/td&gt;
&lt;td id=&quot;c&amp;gt;p=&quot; style=&quot;text-align: left;&quot;&gt;애플의 객체 기반 저장소(Core Data), 또는 SQLite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8002-bec3-cf90c58984cd&quot;&gt;
&lt;td id=&quot;RrVY&quot; style=&quot;text-align: left;&quot;&gt;Web&lt;/td&gt;
&lt;td id=&quot;YRON&quot; style=&quot;text-align: left;&quot;&gt;IndexedDB, LocalStorage&lt;/td&gt;
&lt;td id=&quot;c&amp;gt;p=&quot; style=&quot;text-align: left;&quot;&gt;브라우저에서 클라이언트 데이터 저장 시 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2018cf77-bc66-8075-9d88-f823c04bb8e3&quot;&gt;
&lt;td id=&quot;RrVY&quot; style=&quot;text-align: left;&quot;&gt;Cross-platform&lt;/td&gt;
&lt;td id=&quot;YRON&quot; style=&quot;text-align: left;&quot;&gt;Realm, ObjectBox, Hive&lt;/td&gt;
&lt;td id=&quot;c&amp;gt;p=&quot; style=&quot;text-align: left;&quot;&gt;플랫폼 독립적이며 사용이 쉬움 (특히 Flutter 등에서 인기)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</description>
      <category>DATABASE</category>
      <category>MySQL</category>
      <category>NoSQL</category>
      <category>RDB</category>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/71</guid>
      <comments>https://like-while.tistory.com/71#entry71comment</comments>
      <pubDate>Wed, 28 May 2025 14:48:10 +0900</pubDate>
    </item>
    <item>
      <title>1편: 블루투스란 무엇인가</title>
      <link>https://like-while.tistory.com/70</link>
      <description>&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-origin-width=&quot;358&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtCGA5/btsObUYOM3v/0cnhuOx1h3B4mqenDusQj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtCGA5/btsObUYOM3v/0cnhuOx1h3B4mqenDusQj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtCGA5/btsObUYOM3v/0cnhuOx1h3B4mqenDusQj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtCGA5%2FbtsObUYOM3v%2F0cnhuOx1h3B4mqenDusQj0%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;358&quot; height=&quot;110&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 블루투스 기술을 매일 쓰고 있지만, 블루투스가 정확히 뭔지, 어떻게 동작하는지 자세히 설명하려고 하면 막연해지는 경우가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1년 넘게 블루투스 디바이스를 활용한 서비스를 개발하면서 늘 &quot;언젠가는 제대로 정리해야지&quot;라는 생각을 가지고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 회사를 다니면서 학습한 블루투스에 대해서 이번 기회에 블루투스의 개념부터 동작 원리, 종류까지 개발자 입장에서 알아야 할 내용을 정리해보려 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;블루투스의 정의&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루투스(Bluetooth)는 짧은 거리에서 데이터를 주고받기 위한 무선 통신 기술입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 특징은 다음과 같습니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;근거리 전용: 보통 10m 내외의 거리에서만 연결 가능&lt;/li&gt;
&lt;li&gt;저전력: 배터리를 적게 소모하는 구조&lt;/li&gt;
&lt;li&gt;간편한 연결: 페어링만 되면 자동 연결 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 블루투스는 스마트워치, 체중계, 차량, 이어폰 같은 소형 저전력 기기들과의 통신에 최적화돼 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;블루투스의 역사&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루투스는 꽤 오래된 기술입니다. 기본 개념은 90년대 후반에 등장했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1998년, 블루투스 기술을 표준화하기 위해 Bluetooth SIG(Special Interest Group)라는 단체가 결성되었습니다. 지금도 이 단체가 표준을 관리합니다.&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;이름은 10세기 덴마크의 왕 하랄드 블루투스(Harald Bluetooth)에서 따왔습니다.&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;Bluetooth 1.0 (1999): 낮은 데이터 전송률 (~721 kbps), 불안정한 연결&lt;/li&gt;
&lt;li&gt;Bluetooth 2.0 + EDR: 전송 속도 증가 (~2.1 Mbps)&lt;/li&gt;
&lt;li&gt;Bluetooth 3.0 + HS: 고속 전송을 위해 Wi-Fi(802.11) 채널을 활용. 블루투스는 연결 제어용으로만 사용되며, 실제 데이터는 Wi-Fi로 전송 (~24 Mbps).&lt;/li&gt;
&lt;li&gt;Bluetooth 4.0 / 4.2: BLE(Bluetooth Low Energy) 등장, 저전력 기기 지원&lt;/li&gt;
&lt;li&gt;Bluetooth 5.0 / 5.2: BLE 범위 확대, 속도 향상, 2Mbps 전송, 멀티 디바이스 브로드캐스트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;블루투스 이해를 위한 개념 정리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 주파수 대역이란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;블루투스는 2.4GHz ISM 대역(산업&amp;middot;과학&amp;middot;의료용)을 사용합니다.&lt;/li&gt;
&lt;li&gt;이 대역은 전 세계적으로 면허 없이 사용할 수 있도록 지정된 비면허 주파수 대역으로, 산업, 과학, 의료 기기뿐만 아니라 소형 무선 기기들에 널리 쓰입니다.&lt;/li&gt;
&lt;li&gt;이 주파수는 Wi-Fi, 전자레인지 등도 같이 쓰기 때문에 간섭이 발생하기도 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 2.4GHz이란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2.4기가헤르츠(Gigahertz)는 전파의 주파수 단위입니다.&lt;/li&gt;
&lt;li&gt;1GHz는 10억 헤르츠(1초에 10억 번 진동)이고, 2.4GHz는 1초에 24억 번 전파가 진동한다는 뜻입니다.&lt;/li&gt;
&lt;li&gt;쉽게 말해, 무선 신호가 초당 24억 번 진동하는 주파수를 의미합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OH6Jp/btsOciygRr7/4ZRD5Re7SRExRkFAwhKcK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OH6Jp/btsOciygRr7/4ZRD5Re7SRExRkFAwhKcK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OH6Jp/btsOciygRr7/4ZRD5Re7SRExRkFAwhKcK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOH6Jp%2FbtsOciygRr7%2F4ZRD5Re7SRExRkFAwhKcK0%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;715&quot; height=&quot;182&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;182&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. ISM이란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Industrial, Scientific, and Medical의 약자입니다.&lt;/li&gt;
&lt;li&gt;산업용, 과학용, 의료용 등 비통신 목적으로도 사용되는 주파수 대역이에요.&lt;/li&gt;
&lt;li&gt;이 대역은 면허 없이 자유롭게 쓸 수 있는 비면허 대역으로 지정돼 있어서, 여러 무선 기기가 자유롭게 공유해서 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nJYof/btsOdyAaKWV/8ppS32TKUNdyIpSR9DV43k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nJYof/btsOdyAaKWV/8ppS32TKUNdyIpSR9DV43k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nJYof/btsOdyAaKWV/8ppS32TKUNdyIpSR9DV43k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnJYof%2FbtsOdyAaKWV%2F8ppS32TKUNdyIpSR9DV43k%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;800&quot; height=&quot;320&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 면허 주파수 대역(Licensed Frequency Bands)이란?&lt;/h3&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFV15r/btsObxiFUYj/pxLYrK4Diy4zfK5ZeBJuSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFV15r/btsObxiFUYj/pxLYrK4Diy4zfK5ZeBJuSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFV15r/btsObxiFUYj/pxLYrK4Diy4zfK5ZeBJuSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFV15r%2FbtsObxiFUYj%2FpxLYrK4Diy4zfK5ZeBJuSk%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;693&quot; height=&quot;218&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 비면허 주파수 대역(Unlicensed Frequency Bands)이란?&lt;/h3&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;별도의 면허 없이도 무선 장치가 사용할 수 있기 때문에, 와이파이, 블루투스, 무선 키보드&amp;middot;마우스 등 다양한 기기에 활용됩니다.&lt;/li&gt;
&lt;li&gt;여러 기기가 동시에 같은 대역을 사용하기 때문에 간섭이 발생할 수 있고, 통신 품질이 떨어질 위험도 존재합니다.&lt;/li&gt;
&lt;li&gt;이런 특성 때문에 보통 저전력, 짧은 거리 통신에 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPutCm/btsOcPvErbf/6kLp6pCNnbG4xOZkQFkOP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPutCm/btsOcPvErbf/6kLp6pCNnbG4xOZkQFkOP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPutCm/btsOcPvErbf/6kLp6pCNnbG4xOZkQFkOP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPutCm%2FbtsOcPvErbf%2F6kLp6pCNnbG4xOZkQFkOP1%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;703&quot; height=&quot;182&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;182&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. MAC 주소란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 블루투스 장비는 고유한 MAC 주소를 갖고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MAC 주소(Media Access Control Address)는 네트워크 장치(블루투스, 와이파이 등)에 부여되는 고유 식별자입니다. 보통 6바이트(48비트) 크기이고, 16진수로 표기됩니다&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;00:1A:7D:DA:71:13&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0wu57/btsObosKxa6/H5wOZ0Q6i1BHkIo0CQJJP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0wu57/btsObosKxa6/H5wOZ0Q6i1BHkIo0CQJJP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0wu57/btsObosKxa6/H5wOZ0Q6i1BHkIo0CQJJP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0wu57%2FbtsObosKxa6%2FH5wOZ0Q6i1BHkIo0CQJJP1%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;685&quot; height=&quot;224&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;Mac 주소 사용처
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BLE 스캔을 하면 주변의 블루투스 장비들이 탐지되는데, 이때 MAC 주소(Public Address 또는 Random Address)가 함께 포함되어 제공됩니다.&lt;/li&gt;
&lt;li&gt;어떤 장치가 어떤 MAC 주소를 가졌는지 알 수 있기 때문에, 특정 장치만 골라서 연결하거나, 원하는 장치만 필터링해서 처리할 수 있어요.&lt;/li&gt;
&lt;li&gt;또한, 한 번 페어링한 기기와 재연결할 때도 MAC 주소가 사용돼요. (단, BLE는 대부분 비페어링 상태로도 통신 가능하며, 일반적으로는 디바이스 식별용으로 주로 사용됨)&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;Android에서는 OS 버전에 따라 BLE 스캔 시 제공되는 MAC 주소가 제한될 수 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Android 6.0 (API 23) 이후부터는 위치 권한을 허용하지 않으면 블루투스 기기가 스캔되지 않습니다.&lt;/li&gt;
&lt;li&gt;Android 10 (API 29) 이후부터는 getAddress()를 통한 MAC 주소 접근이 제한되며, 대신 BluetoothDevice.getAddress()가 &amp;ldquo;00:00:00:00:00:00&amp;rdquo;을 반환하는 경우도 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;iOS에서는 BLE 스캔 결과에 MAC 주소가 포함되지 않기 때문에, MAC 주소 대신 식별이 필요할 경우 Advertisement Data의 Manufacturer Data나 Custom Service UUID 등을 활용해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 프로파일(Profile)이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루투스에서는 &amp;ldquo;이 기기를 어떤 용도로 사용할 것인가?&amp;rdquo;를 정리해둔 일종의 표준 통신 형식을 프로파일이라고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4KWF0/btsObuMYGUW/Kl1smSsY8rsR7273Eh2Kw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4KWF0/btsObuMYGUW/Kl1smSsY8rsR7273Eh2Kw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4KWF0/btsObuMYGUW/Kl1smSsY8rsR7273Eh2Kw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4KWF0%2FbtsObuMYGUW%2FKl1smSsY8rsR7273Eh2Kw0%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;762&quot; height=&quot;239&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;블루투스 동작 방식&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 페어링(Pairing)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루투스를 처음 연결할 때, 두 기기는 암호화 키를 교환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 페어링이라고 하고, 한 번 페어링되면 자동 재연결이 가능합니다. BLE에서는 보안 수준을 선택할 수 있으며, 보통 'Just Works', 'Passkey Entry', 'Numeric Comparison' 같은 방식이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Just Works: 사용자가 입력 없이 자동으로 연결됨. 사용자 편의는 좋지만 보안 수준은 낮음.&lt;/li&gt;
&lt;li&gt;Passkey Entry: 한 쪽에 표시된 6자리 숫자를 다른 쪽에 입력. 보안 수준이 높음.&lt;/li&gt;
&lt;li&gt;Numeric Comparison: 양쪽 디바이스에 같은 숫자가 표시되며, 사용자 확인을 통해 페어링.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BLE는 기본적인 데이터 송수신에는 페어링이 필요 없지만, 민감한 데이터 전송이나 보안이 필요한 경우에는 페어링을 통해 암호화 키를 교환해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페어링과 기기 연결은 다른 개념으로 &amp;ldquo;페어링&amp;rdquo;은 보안 키 교환을 위한 절차, &amp;ldquo;연결&amp;rdquo;은 실제 데이터 송수신 가능 상태로 만드는 것입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 페어링 이후의 흐름&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Central(앱)이 주변 BLE 기기를 스캔합니다.&lt;/li&gt;
&lt;li&gt;Peripheral(디바이스)와 연결 시도합니다.&lt;/li&gt;
&lt;li&gt;연결 성공 시 서비스/캐릭터리스틱 탐색합니다.&lt;/li&gt;
&lt;li&gt;데이터 주고받기 (Read/Write/Notify)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;블루투스의 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루투스는 기본적으로 Master/Slave 구조에서 시작했습니다. 각각 통신을 주도하는 쪽과 수신하는 쪽이라는 의미로, 스마트폰과 이어폰 같은 관계입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 BLE에서는 이 구분이 Central/Peripheral로 바뀌었고, Central이 연결을 주도하고 Peripheral이 데이터를 제공합니다. Master/Slave는 기술적인 용어지만, 사회적 맥락에서는 인종차별적 역사를 연상시킬 수 있어서 블루투스 SIG를 비롯해 여러 기술 커뮤니티(예: Python, GitHub 등)에서 표현을 더 중립적으로 바꾸는 움직임이 있었습니다. 깃허브에서도 주 브랜치 이름이 Master에서 Main으로 바뀌었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kB5XC/btsObVXHL8w/fqjrWqs6T8YDVs2vMuUW80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kB5XC/btsObVXHL8w/fqjrWqs6T8YDVs2vMuUW80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kB5XC/btsObVXHL8w/fqjrWqs6T8YDVs2vMuUW80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkB5XC%2FbtsObVXHL8w%2FfqjrWqs6T8YDVs2vMuUW80%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;821&quot; height=&quot;184&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;출처&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.bluetooth.com/learn-about-bluetooth/tech-overview/&quot;&gt;https://www.bluetooth.com/learn-about-bluetooth/tech-overview/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748236147589&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Bluetooth Technology Overview | Bluetooth&amp;reg; Technology Website&quot; data-og-description=&quot;Learn About Bluetooth One key reason for the incredible success of Bluetooth&amp;reg; technology is the tremendous flexibility it provides developers. Offering two radio options&amp;hellip;&quot; data-og-host=&quot;www.bluetooth.com&quot; data-og-source-url=&quot;https://www.bluetooth.com/learn-about-bluetooth/tech-overview/&quot; data-og-url=&quot;https://www.bluetooth.com/learn-about-bluetooth/tech-overview/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ciRKJH/hyYYvG17sw/EM0JP8t6ZsOEHO7jJo4uh0/img.png?width=2987&amp;amp;height=2371&amp;amp;face=1185_690_1614_1119,https://scrap.kakaocdn.net/dn/h9fSR/hyY1kjAFnh/fE6omRKf3pbpVHW6yHDzC1/img.png?width=2987&amp;amp;height=2371&amp;amp;face=1185_690_1614_1119&quot;&gt;&lt;a href=&quot;https://www.bluetooth.com/learn-about-bluetooth/tech-overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.bluetooth.com/learn-about-bluetooth/tech-overview/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ciRKJH/hyYYvG17sw/EM0JP8t6ZsOEHO7jJo4uh0/img.png?width=2987&amp;amp;height=2371&amp;amp;face=1185_690_1614_1119,https://scrap.kakaocdn.net/dn/h9fSR/hyY1kjAFnh/fE6omRKf3pbpVHW6yHDzC1/img.png?width=2987&amp;amp;height=2371&amp;amp;face=1185_690_1614_1119');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Bluetooth Technology Overview | Bluetooth&amp;reg; Technology Website&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn About Bluetooth One key reason for the incredible success of Bluetooth&amp;reg; technology is the tremendous flexibility it provides developers. Offering two radio options&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.bluetooth.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/develop/connectivity/bluetooth?hl=ko&quot;&gt;https://developer.android.com/develop/connectivity/bluetooth?hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748236145665&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;블루투스 개요 &amp;nbsp;|&amp;nbsp; Connectivity &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;이 페이지는 Cloud Translation API를 통해 번역되었습니다. 블루투스 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Android 플랫폼에는 블루투스 네트워크 &quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/develop/connectivity/bluetooth?hl=ko&quot; data-og-url=&quot;https://developer.android.com/develop/connectivity/bluetooth?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/tfbVV/hyY1gapoxz/fX67pR1B4U0thuk3bPbSk1/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/develop/connectivity/bluetooth?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/develop/connectivity/bluetooth?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/tfbVV/hyY1gapoxz/fX67pR1B4U0thuk3bPbSk1/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;블루투스 개요 &amp;nbsp;|&amp;nbsp; Connectivity &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 페이지는 Cloud Translation API를 통해 번역되었습니다. 블루투스 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Android 플랫폼에는 블루투스 네트워크&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>블루투스</category>
      <category>Bluetooth</category>
      <category>블루투스개념정리</category>
      <category>페어링</category>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/70</guid>
      <comments>https://like-while.tistory.com/70#entry70comment</comments>
      <pubDate>Mon, 26 May 2025 14:10:22 +0900</pubDate>
    </item>
    <item>
      <title>HTTP FAILED: java.net.SocketTimeoutException: timeout 문제 해결법</title>
      <link>https://like-while.tistory.com/69</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 운영하던 서비스가 데이터가 많이 쌓여서 api return까지 걸리는 시간이 10초를 넘으면서 사용 기록이 많은 사용자들에게 앱에서 연속적으로 timeOut이 발생했습니다. 현재 상황에서 조회에 소요되는 시간은 30초 전후이고, DB 개선이 필요하지만 동시에 timeOut 제한 시간도 수정을 해야할 것 같습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타임 아웃의 종류&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAZNm4/btsNwqYRMV4/X1jXcZAjkDuu7fLBbcQA0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAZNm4/btsNwqYRMV4/X1jXcZAjkDuu7fLBbcQA0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAZNm4/btsNwqYRMV4/X1jXcZAjkDuu7fLBbcQA0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAZNm4%2FbtsNwqYRMV4%2FX1jXcZAjkDuu7fLBbcQA0k%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;648&quot; height=&quot;240&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정할 수 있는 값의 범위는부터 0 부터 Integer.MAX_VALUE까지이며, 단위는 밀리초(ms)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0은 제한 없음(no timeout)을 의미합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;타임아웃 종류&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;223&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byKyaG/btsNwvFOYEm/dzgJ4TFsXzcnHREbvbFlo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byKyaG/btsNwvFOYEm/dzgJ4TFsXzcnHREbvbFlo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byKyaG/btsNwvFOYEm/dzgJ4TFsXzcnHREbvbFlo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyKyaG%2FbtsNwvFOYEm%2FdzgJ4TFsXzcnHREbvbFlo0%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;698&quot; height=&quot;223&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;SocketTimeOutException이 발생할 수 있는 상황&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 서버 응답 지연&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버가 내부적으로 오래 걸리는 작업을 처리 중일 수 있습니다 (예: 데이터베이스 작업, 외부 API 호출).&lt;/li&gt;
&lt;li&gt;이 경우에는 readTimeout에 걸려서 타임아웃 발생합니다.&lt;/li&gt;
&lt;li&gt;저는 이 경우에 해당합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시: 서버 응답에 28초 소요, readTimeout이 기본 10초 &amp;rarr; SocketTimeoutException&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 네트워크 품질 불량 또는 끊김&lt;/h3&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;패킷 손실 (packet loss)&lt;/li&gt;
&lt;li&gt;지연 (latency)&lt;/li&gt;
&lt;li&gt;DNS 지연 또는 실패&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시: 지하철에서 약한 LTE 신호로 요청 보냈을 때 응답이 안 오고 timeout 발생&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 서버가 다운되었거나 연결 자체가 안 되는 경우&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이건 보통 connectTimeout에 해당합니다.&lt;/li&gt;
&lt;li&gt;서버가 아예 꺼져 있거나 IP/포트가 잘못되어 연결을 못 하면 타임아웃아 발생합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시: 잘못된 서버 주소를 넣었거나, 서버가 꺼져 있음 &amp;rarr; 연결 자체가 실패&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 프록시, 방화벽, VPN 등의 중간 장비가 연결을 방해&lt;/h3&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;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시: 프록시 서버가 서버 응답을 받아도 클라이언트로 전달 안 해주는 경우&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타임아웃 제한 수정 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;okhttpClient에 아래와 같이 적용했습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;val okhttpClient = OkHttpClient.Builder()
  .connectTimeout(30, TimeUnit.SECONDS)
  .readTimeout(30, TimeUnit.SECONDS)
  .writeTimeout(30, TimeUnit.SECONDS)
  .callTimeout(60, TimeUnit.SECONDS)
.build()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;201&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nLl74/btsNwuAfDvd/ms3KMz8lb8WwgSj0HGPOo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nLl74/btsNwuAfDvd/ms3KMz8lb8WwgSj0HGPOo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nLl74/btsNwuAfDvd/ms3KMz8lb8WwgSj0HGPOo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnLl74%2FbtsNwuAfDvd%2Fms3KMz8lb8WwgSj0HGPOo1%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;644&quot; height=&quot;201&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;201&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>질문 정리</category>
      <category>connecttimeout</category>
      <category>okhttp</category>
      <category>sockettimeoutexception</category>
      <category>Timeout</category>
      <category>타임아웃</category>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/69</guid>
      <comments>https://like-while.tistory.com/69#entry69comment</comments>
      <pubDate>Thu, 24 Apr 2025 11:19:30 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 앱의 기본 빌드 타입을 Release로 변경하는 방법</title>
      <link>https://like-while.tistory.com/68</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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 안드로이드 스튜디오에서 앱을 실행하거나 빌드하면, 기본적으로 debug 빌드 타입으로 앱이 빌드됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 서비스와 동일한 환경에서 테스트하거나, 디버깅 로그 없이 앱을 실행하고 싶을 때는 release 빌드로 앱을 실행하고 싶은 경우에는 빌드 세팅을 바꿔야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드 스튜디오는 기본적으로 debug를 기본 빌드 타입으로 인식하며, 실행(Run) 버튼을 눌러도 항상 debug 빌드가 실행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;난독화(ProGuard)가 적용되지 않음&lt;/li&gt;
&lt;li&gt;최적화되지 않은 상태로 앱이 동작&lt;/li&gt;
&lt;li&gt;릴리즈 빌드에서 발생하는 버그를 사전에 확인할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문제를 해결하기 위해, 기본 빌드 타입을 release로 변경하고 앱을 실행하는 방법을 알아보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 빌드 타입(Build Type)이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Build Type은 안드로이드 앱을 빌드할 때, 빌드 설정을 구분하는 단위입니다. 대표적으로 debug와 release 두 가지가 기본으로 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 타입 설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;debug&lt;/td&gt;
&lt;td&gt;개발 중 디버깅에 최적화된 빌드디버그 로그 출력, 프로가드 미적용, 서명 생략&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;release&lt;/td&gt;
&lt;td&gt;사용자에게 배포 가능한 최종 앱 빌드로그 제거, 코드 난독화, 최적화, 서명 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 빌드 타입은 build.gradle의 buildTypes 블록 안에서 설정할 수 있습니다:&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;buildTypes {
    release {
        isMinifyEnabled = true
        versionNameSuffix = &quot;&quot;
        proguardFiles(
            getDefaultProguardFile(&quot;proguard-android-optimize.txt&quot;),
            &quot;proguard-rules.pro&quot;
        )
        signingConfig = signingConfigs.getByName(&quot;release&quot;)
    }

    debug {
        isMinifyEnabled = true
        versionNameSuffix = &quot;.debug&quot;
        proguardFiles(
            getDefaultProguardFile(&quot;proguard-android-optimize.txt&quot;),
            &quot;proguard-rules.pro&quot;,
        )
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 기본 빌드 타입을 Release로 변경하는 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드 스튜디오에서 실행(Run) 시 자동으로 release 빌드가 실행되도록 설정하려면 아래 방법 중 하나를 선택하면 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 방법 0. signingkey 발급(signingkey가 있다면 생략 가능)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-22 144113.png&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BbYzX/btsNuIDHAqb/KGrrlkdfxwaukBLSHiKvj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BbYzX/btsNuIDHAqb/KGrrlkdfxwaukBLSHiKvj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BbYzX/btsNuIDHAqb/KGrrlkdfxwaukBLSHiKvj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBbYzX%2FbtsNuIDHAqb%2FKGrrlkdfxwaukBLSHiKvj1%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;731&quot; height=&quot;390&quot; data-filename=&quot;스크린샷 2025-04-22 144113.png&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-22 144305.png&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5KMci/btsNruNHfI5/klMcKhpsnYrBY5W91CAttk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5KMci/btsNruNHfI5/klMcKhpsnYrBY5W91CAttk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5KMci/btsNruNHfI5/klMcKhpsnYrBY5W91CAttk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5KMci%2FbtsNruNHfI5%2FklMcKhpsnYrBY5W91CAttk%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;1042&quot; height=&quot;508&quot; data-filename=&quot;스크린샷 2025-04-22 144305.png&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상단 메뉴에서&lt;/b&gt; Build &amp;gt; Generate Signed Bundle / APK.. 선택&lt;/li&gt;
&lt;li&gt;Android App Bundle 옵션 선택 후 Next&lt;/li&gt;
&lt;li&gt;Create new .. 선택 후 Key 정보 입력 후 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 경로와 Alias, Password은 이후 모드 설정에 필요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 방법 1. Release 모드 설정 생성&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9VMCo/btsNuZznjCC/v8pYIMtbhjwb82yMvNu35K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9VMCo/btsNuZznjCC/v8pYIMtbhjwb82yMvNu35K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9VMCo/btsNuZznjCC/v8pYIMtbhjwb82yMvNu35K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9VMCo%2FbtsNuZznjCC%2Fv8pYIMtbhjwb82yMvNu35K%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;1000&quot; height=&quot;539&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상단 메뉴에서&lt;/b&gt; Run &amp;gt; Edit Configurations 클릭&lt;/li&gt;
&lt;li&gt;앱 모듈의 설정에서 Signing Configs를 선택&lt;/li&gt;
&lt;li&gt;release 가 없다면 +버튼을 눌러서 생성&lt;/li&gt;
&lt;li&gt;SigningKey를 생성했을 때, 키 정보를 입력 및 저장&lt;/li&gt;
&lt;li&gt;해당 과정을 거치면 build.gradle에 release 빌드를 위한 설정이 적용&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;build.gradle이 변경되는 과정에서 원래 build.gradle의 일부 코드가 소실될 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 방법 2. Run/Debug Configuration 설정 변경&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;905&quot; data-origin-height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5WUhf/btsNuwYKXaN/hbdkk9KkzuLr4pXt1V6ORK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5WUhf/btsNuwYKXaN/hbdkk9KkzuLr4pXt1V6ORK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5WUhf/btsNuwYKXaN/hbdkk9KkzuLr4pXt1V6ORK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5WUhf%2FbtsNuwYKXaN%2Fhbdkk9KkzuLr4pXt1V6ORK%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;905&quot; height=&quot;376&quot; data-origin-width=&quot;905&quot; data-origin-height=&quot;376&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Shift를 두번 눌러서 build variants를 검색하거나 오른쪽 하단의 build variants 탭을 눌러서 접근 가능&lt;/li&gt;
&lt;li&gt;Build Variants에서 release 모드로 변경&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, release 빌드는 signingConfig 설정이 필요하며 서명이 없으면 실행이 안 될 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 방법 2-1. build.gradle에서 기본 빌드 Variant 설정 (Gradle Task 용도)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 자동화 목적으로 사용할 경우, Gradle 명령어를 통해 release 빌드를 직접 실행할 수도 있습니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;./gradlew assembleRelease
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹은 APK 설치까지 진행하고 싶다면 다음의 방식을 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;./gradlew installRelease
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;⚠️ 주의 사항&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-24 102439.png&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;653&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4LZfd/btsNx0Ylz9d/kqqeBtAHC2na1Z7lJeqy3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4LZfd/btsNx0Ylz9d/kqqeBtAHC2na1Z7lJeqy3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4LZfd/btsNx0Ylz9d/kqqeBtAHC2na1Z7lJeqy3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4LZfd%2FbtsNx0Ylz9d%2FkqqeBtAHC2na1Z7lJeqy3k%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;716&quot; height=&quot;653&quot; data-filename=&quot;스크린샷 2025-04-24 102439.png&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;653&quot;/&gt;&lt;/span&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;위의 문제가 발생한다면 하단과 같이 release 안에 signingConfig 설정 코드를 넣어줘야합니다.&lt;/li&gt;
&lt;li&gt;release 빌드는 반드시 서명 설정이 필요합니다 (signingConfigs 설정 누락 시 빌드 실패)&lt;/li&gt;
&lt;li&gt;디버깅이 제한되므로, 디버깅이 필요한 경우에는 debuggable true 설정을 임시로 추가할 수 있습니다 (단 보안상 권장되지 않음)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;buildTypes {
    release {
    	...
        signingConfig = signingConfigs.getByName(&quot;release&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>질문 정리</category>
      <category>Android Studio</category>
      <category>build type</category>
      <category>release build</category>
      <category>디버그 빌드</category>
      <category>릴리즈 빌드</category>
      <category>빌드 타입</category>
      <category>안드로이드</category>
      <category>안드로이드 스튜디오</category>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/68</guid>
      <comments>https://like-while.tistory.com/68#entry68comment</comments>
      <pubDate>Tue, 22 Apr 2025 14:59:01 +0900</pubDate>
    </item>
    <item>
      <title>baseUrl 설정 과정에서 일부 경로가 호출 URL에 반영되지 않는 문제</title>
      <link>https://like-while.tistory.com/67</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 서버 이전을 하면서 레거시 코드를 고치게 되었는데, 도메인 및 기타 하위 경로가 변경되었습니다. baseUrl을 변경한 후, 일부 경로가 호출 URL에 반영되지 않는 문제가 있어서, 정리해봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 baseUrl에는 도메인 주소까지만 작성되어있었습니다. 하지만 한 앱에서 하위 경로도 모두 동일하게 사용하는 부분이 있어서 해당 부분까지 포함해서 BaseUrl에 넣어뒀습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 https://like.while.android/api/v1/ 와 같은 형식으로 입력했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;baseUrl을 https://like.while.android/api/v1/로 설정했는데도, 실제 API 호출 시 /api/v1/가 생략되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 &lt;b&gt;interface의 endpoint path 설정&lt;/b&gt;에서 @GET, @POST 등에 &lt;b&gt;슬래시(/)로 시작되는 절대 경로&lt;/b&gt;를 사용했기 때문이었습니다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;interface ApiService {
    @GET(&quot;/users&quot;) // &amp;larr; 슬래시로 시작 &amp;rarr; baseUrl 무시하고 절대 경로
    suspend fun getUsers(): Response&amp;lt;List&amp;lt;User&amp;gt;&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우, https://like.while.android/users 로 호출되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, baseUrl에 포함했던 /api/v1/ 경로가 무시된 채 API가 호출되었습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@GET이나 @POST 등에서 &lt;b&gt;절대 경로가 아닌 상대 경로로 설정해야합니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;interface ApiService {
    @GET(&quot;users&quot;) // &amp;larr; 슬래시 없음 &amp;rarr; baseUrl 뒤에 붙음
    suspend fun getUsers(): Response&amp;lt;List&amp;lt;User&amp;gt;&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 최종 URL은 이 경우, https://app.nueyne.dev/api/v1/users 로 호출되었습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 절대 경로 (Absolute Path)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기준(baseUrl)을 무시하고&lt;/b&gt; 지정한 경로 그대로 요청하는 방식&lt;/li&gt;
&lt;li&gt;경로 앞에 슬래시(/)가 붙어 있음&lt;/li&gt;
&lt;li&gt;baseUrl의 경로 부분(/api/v1/ 등)이 &lt;b&gt;무시&lt;/b&gt;됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@GET(&quot;/users&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;baseUrl이 https://like.while.android/api/v1/라고 해도, @GET(&quot;/users&quot;) 처럼 절대 경로를 사용하면 최종 호출 URL은 다음과 같이 됩니다&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;https://like.while.android/api/v1/&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;https://like.while.android/users&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 상대 경로 (Relative Path)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기준(baseUrl)&lt;/b&gt; 에 경로가 &lt;b&gt;이어붙는 방식&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;슬래시(/) 없이 시작하는 게 특징&lt;/li&gt;
&lt;li&gt;baseUrl을 기준으로 경로가 연결됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@GET(&quot;users&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;baseUrl이라면 최종 호출 URL은 이렇게 됩니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;https://like.while.android/api/v1/&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;https://like.while.android/api/v1/users&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@GET(&quot;/something&quot;) &amp;rarr; baseUrl의 path는 무시됨&lt;/li&gt;
&lt;li&gt;@GET(&quot;something&quot;) &amp;rarr; baseUrl 뒤에 붙음 (원하는 동작)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절대 경로와 상대 경로의 개념이었습니다. 대학교 때 파일 처리라는 과목을 수강하면서 배웠던 개념이 여기에 적용되어있었던 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 프로젝트의 baseUrl은 https://1.123.4.567:1234 와 같은 형식으로 입력되어있고, 그 뒤에 @GET(&quot;/users&quot;) 로 주소를 붙여서 사용하는 방식으로 동작하고 있던 것이 제 변경 후 호출 URL이 이상해진 근본적인 이유였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 제가 아는 바에 따르면 baseUrl은 /로 끝나지 않으면 오류가 발생하는 것으로 알고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 프로젝트는 baseUrl을 https://1.123.4.567:1234와 같은 형식으로 사용했고, 문제가 발생하지 않았습니다. 이유는 다음과 같습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅URL의 기본 구조&lt;/h2&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;https://like.while.android:443/api/v1/users?sort=asc#section2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;프로토콜 (scheme)&lt;/td&gt;
&lt;td&gt;통신 방식&lt;/td&gt;
&lt;td&gt;http, https&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;호스트 (host)&lt;/td&gt;
&lt;td&gt;접속할 도메인 이름 또는 IP 주소&lt;/td&gt;
&lt;td&gt;like.while.android, 1.123.4.567&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;포트 (port)&lt;/td&gt;
&lt;td&gt;서버와 통신할 때 사용하는 포트 (생략 가능, https는 443)&lt;/td&gt;
&lt;td&gt;:443, :8000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;패스 (path)&lt;/td&gt;
&lt;td&gt;서버 내부에서 요청 자원을 찾기 위한 경로&lt;/td&gt;
&lt;td&gt;/api/v1/example&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;쿼리스트링 (query)&lt;/td&gt;
&lt;td&gt;파라미터 전달용&lt;/td&gt;
&lt;td&gt;?sort=asc, ?page=1&amp;amp;limit=20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;프래그먼트 (fragment)&lt;/td&gt;
&lt;td&gt;페이지 내부 특정 위치로 이동 (서버에는 전송되지 않음)&lt;/td&gt;
&lt;td&gt;#section2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 핵심 용어 정리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;도메인 (Domain)&lt;/b&gt;&lt;/h3&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;IP 대신 사용하며, DNS가 이를 IP로 변환해줍니다.&lt;/li&gt;
&lt;li&gt;예: google.com, naver.com,like.while.android&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;호스트 (Host)&lt;/b&gt;&lt;/h3&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;를 의미하며, 도메인이나 IP가 될 수 있어요.&lt;/li&gt;
&lt;li&gt;like.while.android &amp;rarr; 하위 도메인을 포함한 전체 호스트 이름&lt;/li&gt;
&lt;li&gt;http://1.123.4.567:443 에서도 1.123.4.567이 host&lt;/li&gt;
&lt;li&gt;Retrofit에서 baseUrl의 호스트는 프로토콜 + 호스트 + 포트까지입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. &lt;b&gt;패스 (Path)&lt;/b&gt;&lt;/h3&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;/li&gt;
&lt;li&gt;/api/v1/users 같은 것&lt;/li&gt;
&lt;li&gt;파일 시스템처럼 &lt;b&gt;계층적 구조&lt;/b&gt;를 가짐&lt;/li&gt;
&lt;li&gt;예: /api/v1/ 는 API 버전 구분을 위한 경로&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ Retrofit에서 baseUrl의 규칙&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Retrofit은 내부적으로 HttpUrl (OkHttp의 클래스)을 사용해 URL을 조립합니다. 이때 다음과 같은 &lt;b&gt;규칙&lt;/b&gt;이 적용돼요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;baseUrl은 반드시 프로토콜(https://)과 도메인, 그리고 /로 끝나는 path로 설정되어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 path가 있다면, 그것도 마지막에 /가 붙어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 다음은 정상적인 baseUrl입니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;https://like.while.android/         
https://like.while.android/api/
https://like.while.android/api/v1/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 다음은 &lt;b&gt;오류 발생합니다&lt;/b&gt; (Retrofit 초기화 시 IllegalArgumentException)&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;https://like.while.android/api&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Retrofit은 baseUrl과 @GET 등에서 정의한 endpoint를 단순 문자열로 이어붙이지 않고, OkHttp의 HttpUrl.Builder를 통해 합성합니다. 이때 baseUrl이 /로 끝나지 않으면 마지막 path segment가 &quot;덮어쓰기&quot; 되기 때문에 의도한 경로와 달라질 수 있다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;✅그런데 왜 https://1.123.4.567:1234 는 괜찮았을까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;https://1.123.4.567:1234 는 path가 없는 URL입니다. 즉, 도메인만 있고 경로(path)가 없기 때문에, Retrofit이 내부적으로 자동으로 /를 붙여서 처리합니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;https://1.123.4.567:1234&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 url은 실제로는 다음과 동일하게 해석됩니다&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;http://1.123.4.567:1234&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 Retrofit 내부에서 OkHttp가 자동으로 처리해주는 부분입니다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;정리2&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;baseUrl은 경로(path)가 있다면 반드시 /로 끝나야 함&lt;/li&gt;
&lt;li&gt;경로가 없는 경우 (host:port만 있는 경우), Retrofit이 &lt;b&gt;자동으로 슬래시를 붙여줌&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;그래서 https://1.123.4.567:1234는 괜찮았던 것입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 사용하는 라이브러리에서 또 새로운 점을 알게 되어서 재밌었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>질문 정리</category>
      <category>Android</category>
      <category>api 경로</category>
      <category>baseurl</category>
      <category>okhttp</category>
      <category>REST API</category>
      <category>retrofit</category>
      <category>Retrofit2</category>
      <category>상대경로</category>
      <category>안드로이드</category>
      <category>절대경로</category>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/67</guid>
      <comments>https://like-while.tistory.com/67#entry67comment</comments>
      <pubDate>Fri, 18 Apr 2025 17:13:09 +0900</pubDate>
    </item>
    <item>
      <title>소프트웨어 정적 분석(Static Analysis)이란?</title>
      <link>https://like-while.tistory.com/66</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 상황&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;b&gt;정적 분석 정의&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;b&gt;정적 분석 필요성&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;품질 향상:&lt;/b&gt; 개발 초기 단계에서 코드의 버그와 취약점을 식별하여 수정함으로써 소프트웨어의 전반적인 품질을 향상 시킬 수 있습니다. 이는 추후 발생할 수 있는 오류를 미연에 방지하고, 유지 보수 비용을 줄이는 데 도움을 줍니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 강화:&lt;/b&gt; 보안 취약점을 조기에 발견하고 해결함으로써 소프트웨어의 보안 수준을 강화할 수 있습니다. 이는 특히 금융, 의료, 국방 등 보안이 중요한 분야에서 더욱 중요합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;표준 준수:&lt;/b&gt; 코딩 표준과 컨벤션을 준수함으로써 개발자 간의 코드 이해도를 높이고 협업을 촉진할 수 있습니다. 또한, 특정 산업 표준이나 규제 요구사항을 충족시키기 위해 정적 분석이 필요할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발 효율성 증가:&lt;/b&gt; 초기에 문제를 발견하고 수정함으로써 개발 과정에서의 지연을 줄이고, 제품 출시 시간을 단축할 수 있습니다.&lt;/li&gt;
&lt;/ol&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;b&gt;사용중인 정적 분석 도구 : ktlint&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 현재 ktlint를 사용하고 있습니다. ktlint 도 Kotlin 프로그래밍 언어를 위한 정적 코드 분석 도구입니다. 이 툴은 Kotlin 코드의 스타일과 포맷팅을 체크하여, 코드의 일관성과 가독성을 향상시키는 데 도움을 줍니다. ktlint는 Kotlin 공식 코딩 스타일 가이드를 기반으로 작동하지만, 사용자 정의 규칙을 추가하여 특정 프로젝트나 팀의 요구사항에 맞춰 조정할 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;주요 특징&lt;/h4&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;: Kotlin의 공식 코딩 스타일을 따르도록 코드를 분석하고, 일관되지 않은 스타일 사용을 지적합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동 수정&lt;/b&gt;: ktlint -F 명령어를 사용하면, 대부분의 스타일 이슈를 자동으로 수정할 수 있습니다. 이는 개발자가 수동으로 코드 스타일 문제를 수정하는 시간을 절약할 수 있게 해줍니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;플러그인 지원&lt;/b&gt;: IntelliJ IDEA와 같은 IDE나, Gradle, Maven과 같은 빌드 도구에 플러그인 형태로 통합할 수 있어, 개발 과정에서 실시간으로 코드 스타일을 검토하고 수정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자 정의 규칙&lt;/b&gt;: 기본 제공되는 규칙 외에도, 팀의 특정 코딩 규칙을 정의하여 적용할 수 있습니다. 이를 통해 팀 내 코드 스타일의 일관성을 유지할 수 있습니다.&lt;/li&gt;
&lt;/ul&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;b&gt;이번에 맞긴 정적 분석 : 스패로우&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 스패로우에 코드를 보내서 받은 정적 분석 리포트가 387 페이지였습니다. 초기 정적 분석은 단순히 단어와 문법만 확인했기 때문에 지금보다 오탐지의 확률이 높았다고 한다. 현재는 개선된 버전이라고 하는데, 이번에 정적 분석 리포트에서 hilt에 대한 코드들이 다 매우 위험으로 감지되었다. 해당 라이브러리는 Android Developers에서 추천하는 것이라서 당황스러웠다. 해당 부분이 1000개 정도 감지된 위험 요소의 80% 정도를 차지하고 있었는데, 실제로 보안 위험이 있는지는 좀 더 조사해봐야할 것 같다. 하지만 종종 오탐지가 보인다. 따라서 무조건 신뢰하기 보다는 참고 용도로 사용하는 것이 좋을 것 같다.&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;b&gt;참고 링크&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sparrow.im/kr/product/sast/&quot;&gt;https://sparrow.im/kr/product/sast/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1725760392022&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Sparrow SAST | 소스코드 취약점 분석 | 시큐어코딩 | 정적 분석&quot; data-og-description=&quot;소스코드 취약점을 분석해 해결 방안을 제공하는 정적 분석 도구로 Sparrow SAST를 활용해 소프트웨어 보안약점 진단가이드, 전자금융감독규정 등을 준수하세요.&quot; data-og-host=&quot;sparrow.im&quot; data-og-source-url=&quot;https://sparrow.im/kr/product/sast/&quot; data-og-url=&quot;https://sparrow.im/kr/product/sast/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xzc9V/hyWY9lwPfp/aFdbe3VNe7nyKYGdqDc14K/img.jpg?width=833&amp;amp;height=833&amp;amp;face=0_0_833_833,https://scrap.kakaocdn.net/dn/bpo8tg/hyWZd2vb3T/n4H5WVRMCPVDqCgkmWnb8K/img.jpg?width=833&amp;amp;height=833&amp;amp;face=0_0_833_833,https://scrap.kakaocdn.net/dn/oqwm9/hyWY9lwPie/v95KkrFffDTARQsPrk9bf0/img.png?width=707&amp;amp;height=533&amp;amp;face=0_0_707_533&quot;&gt;&lt;a href=&quot;https://sparrow.im/kr/product/sast/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sparrow.im/kr/product/sast/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xzc9V/hyWY9lwPfp/aFdbe3VNe7nyKYGdqDc14K/img.jpg?width=833&amp;amp;height=833&amp;amp;face=0_0_833_833,https://scrap.kakaocdn.net/dn/bpo8tg/hyWZd2vb3T/n4H5WVRMCPVDqCgkmWnb8K/img.jpg?width=833&amp;amp;height=833&amp;amp;face=0_0_833_833,https://scrap.kakaocdn.net/dn/oqwm9/hyWY9lwPie/v95KkrFffDTARQsPrk9bf0/img.png?width=707&amp;amp;height=533&amp;amp;face=0_0_707_533');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Sparrow SAST | 소스코드 취약점 분석 | 시큐어코딩 | 정적 분석&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소스코드 취약점을 분석해 해결 방안을 제공하는 정적 분석 도구로 Sparrow SAST를 활용해 소프트웨어 보안약점 진단가이드, 전자금융감독규정 등을 준수하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sparrow.im&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/training/dependency-injection/hilt-android?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.android.com/training/dependency-injection/hilt-android?hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1725760419546&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Hilt를 사용한 종속 항목 삽입 &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;이 페이지는 Cloud Translation API를 통해 번역되었습니다. Hilt를 사용한 종속 항목 삽입 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Hilt는 프로젝트에서 종속&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/training/dependency-injection/hilt-android?hl=ko&quot; data-og-url=&quot;https://developer.android.com/training/dependency-injection/hilt-android?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ixljW/hyWZm6eTk0/3qQJB0K5aXeVYLIHtmEc40/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/training/dependency-injection/hilt-android?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/training/dependency-injection/hilt-android?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ixljW/hyWZm6eTk0/3qQJB0K5aXeVYLIHtmEc40/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Hilt를 사용한 종속 항목 삽입 &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 페이지는 Cloud Translation API를 통해 번역되었습니다. Hilt를 사용한 종속 항목 삽입 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Hilt는 프로젝트에서 종속&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/66</guid>
      <comments>https://like-while.tistory.com/66#entry66comment</comments>
      <pubDate>Sun, 8 Sep 2024 10:53:45 +0900</pubDate>
    </item>
    <item>
      <title>Firebase Cloud Messageing 수신 기능 구현(Compose)</title>
      <link>https://like-while.tistory.com/65</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2024-08-28 153202.png&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y1tI4/btsJhnFnJNb/1pqJRBYP0zm5O4f4V7nZgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y1tI4/btsJhnFnJNb/1pqJRBYP0zm5O4f4V7nZgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y1tI4/btsJhnFnJNb/1pqJRBYP0zm5O4f4V7nZgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY1tI4%2FbtsJhnFnJNb%2F1pqJRBYP0zm5O4f4V7nZgk%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;633&quot; height=&quot;163&quot; data-filename=&quot;화면 캡처 2024-08-28 153202.png&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;firebase 프로젝트 생성 및 google-service.json 파일 다운로드&lt;/li&gt;
&lt;li&gt;필요한 종속성을 build.gradle에 선언&lt;/li&gt;
&lt;li&gt;AndroidManifest에 service 추가&lt;/li&gt;
&lt;li&gt;FirebaseMessagingService을 상속 받아서 구현&lt;/li&gt;
&lt;/ol&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;Firebase Cloud Messaging을 활용하여 앱에서 프로모션 알림을 수신하고 처리하는 구현 방법을 다음 단계별로 설명합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;&lt;b&gt;1. 프로젝트 설정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;google-services.json 파일을 프로젝트에 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2024-08-28 153855.png&quot; data-origin-width=&quot;382&quot; data-origin-height=&quot;261&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OS4Vm/btsJh1BR3ZO/KuvXNIcvsuvAEe7XtdJJRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OS4Vm/btsJh1BR3ZO/KuvXNIcvsuvAEe7XtdJJRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OS4Vm/btsJh1BR3ZO/KuvXNIcvsuvAEe7XtdJJRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOS4Vm%2FbtsJh1BR3ZO%2FKuvXNIcvsuvAEe7XtdJJRK%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;382&quot; height=&quot;261&quot; data-filename=&quot;화면 캡처 2024-08-28 153855.png&quot; data-origin-width=&quot;382&quot; data-origin-height=&quot;261&quot;/&gt;&lt;/span&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;필요한 종속성을 build.gradle에 선언합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// app
plugins {
    id(&quot;com.google.gms.google-services&quot;)
}

dependencies {
    implementation(&quot;com.google.firebase:firebase-messaging-ktx&quot;)		
}

// project
plugins {
    id(&quot;com.google.gms.google-services&quot;) version &quot;4.4.0&quot; apply false
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AndroidManifest.xml에 service를 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;service
    android:name=&quot;.data.remote.FcmService&quot;
    android:exported=&quot;false&quot;&amp;gt;
    &amp;lt;intent-filter&amp;gt;
        &amp;lt;action android:name=&quot;com.google.firebase.MESSAGING_EVENT&quot; /&amp;gt;
    &amp;lt;/intent-filter&amp;gt;
&amp;lt;/service&amp;gt;
&lt;/code&gt;&lt;/pre&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;&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;2. FirebaseMessaging Service&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FirebaseMessagingService를 상속 받아서 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;  &lt;b&gt;onNewToken 메서드가 불리는 경우&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;앱 설치 시&lt;/b&gt;: 사용자가 앱을 처음 설치하고 실행할 때, 새로운 FCM 등록 토큰이 생성되며, 이 때 onNewToken이 호출됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;앱 데이터 삭제 후 재설치 시&lt;/b&gt;: 사용자가 앱 데이터를 삭제하거나 앱을 제거했다가 다시 설치하는 경우, 기존의 토큰이 삭제되고 새 토큰이 발급될 때 이 메서드가 실행됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;토큰이 갱신되는 경우&lt;/b&gt;: FCM 토큰은 주기적으로 갱신될 수 있습니다. 이는 보안을 유지하기 위해 필요한 절차로, 갱신 주기는 Firebase 서비스에 의해 관리됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;앱의 보안 관련 설정 변경 시&lt;/b&gt;: 예를 들어, 사용자가 앱의 인스턴스 ID를 초기화하거나 FCM 관련 정보를 재설정하는 경우, 새로운 토큰이 필요하게 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기기 설정 변경 시&lt;/b&gt;: 사용자가 Google 계정을 추가하거나 변경하는 등의 기기 설정을 수정할 때, FCM 시스템이 토큰을 새로 발급할 수 있습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@AndroidEntryPoint
class FcmService : FirebaseMessagingService() {
    @Inject
    lateinit var appPreferences: AppPreferences

    override fun onNewToken(token: String) {
        super.onNewToken(token)
        LogUtils.d(&quot;new token : $token&quot;)
        appPreferences.saveFcmToken(token)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;&lt;b&gt;3. 알림 메시지 처리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;onMessageReceived 메서드를 오버라이드하여 수신된 메시지를 처리합니다.&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;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@AndroidEntryPoint
class FcmService : FirebaseMessagingService() {

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        LogUtils.d(&quot;From: ${remoteMessage.from}&quot;)

        // 알림 메시지인 경우
        if (remoteMessage.notification != null) {
            LogUtils.d(&quot;Message Notification Body: ${remoteMessage.notification?.body}&quot;)
            showNotification(remoteMessage.notification?.title, remoteMessage.notification?.body)
        }
    }

    private fun showNotification(title: String?, body: String?) {
        val notificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val channel = NotificationChannel(
            FCM_NOTIFICATION_NAME,
            &quot;Notification&quot;,
            NotificationManager.IMPORTANCE_HIGH
        )
        notificationManager.createNotificationChannel(channel)

        val notificationBuilder = NotificationCompat.Builder(this, FCM_NOTIFICATION_NAME)
            .setContentTitle(title ?: &quot;Promotion Title&quot;)
            .setContentText(body ?: &quot;Promotion Message&quot;)
            .setSmallIcon(android.R.drawable.ic_dialog_email)
            .setAutoCancel(true)

        notificationManager.notify(FCM_NOTIFICATION_ID, notificationBuilder.build())
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 단계를 통해, 사용자가 앱을 사용하고 있지 않을 때도 프로모션 알림을 효과적으로 수신하고, 적절히 반응할 수 있도록 하는 시스템을 구축할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고 링크&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://firebase.blog/posts/2023/08/adding-fcm-to-jetpack-compose-app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://firebase.blog/posts/2023/08/adding-fcm-to-jetpack-compose-app/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724827649391&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;The Firebase Blog&quot; data-og-description=&quot;News, tutorials, and updates from the Firebase team.&quot; data-og-host=&quot;firebase.blog&quot; data-og-source-url=&quot;https://firebase.blog/posts/2023/08/adding-fcm-to-jetpack-compose-app/&quot; data-og-url=&quot;https://firebase.blog/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ejqVt5/hyWVSwwG8v/7xnMk2jHRTxgabk2xKGjkK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bqsLnI/hyWVQMewJt/nRwlR4GPmKPdanKgu9clBK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bPUcUn/hyWVWr9rVT/iCYFQovDHnOKoKe1PtQcJK/img.jpg?width=212&amp;amp;height=212&amp;amp;face=68_42_126_105&quot;&gt;&lt;a href=&quot;https://firebase.blog/posts/2023/08/adding-fcm-to-jetpack-compose-app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.blog/posts/2023/08/adding-fcm-to-jetpack-compose-app/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ejqVt5/hyWVSwwG8v/7xnMk2jHRTxgabk2xKGjkK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bqsLnI/hyWVQMewJt/nRwlR4GPmKPdanKgu9clBK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bPUcUn/hyWVWr9rVT/iCYFQovDHnOKoKe1PtQcJK/img.jpg?width=212&amp;amp;height=212&amp;amp;face=68_42_126_105');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;The Firebase Blog&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;News, tutorials, and updates from the Firebase team.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;firebase.blog&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/cloud-messaging/android/client?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://firebase.google.com/docs/cloud-messaging/android/client?hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724827667047&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Android에서 Firebase 클라우드 메시징 클라이언트 앱 설정&quot; data-og-description=&quot;Google I/O 2023에서 Firebase의 주요 소식을 확인하세요. 자세히 알아보기 의견 보내기 Android에서 Firebase 클라우드 메시징 클라이언트 앱 설정 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐&quot; data-og-host=&quot;firebase.google.com&quot; data-og-source-url=&quot;https://firebase.google.com/docs/cloud-messaging/android/client?hl=ko&quot; data-og-url=&quot;https://firebase.google.com/docs/cloud-messaging/android/client?hl=ko&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/cloud-messaging/android/client?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.google.com/docs/cloud-messaging/android/client?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Android에서 Firebase 클라우드 메시징 클라이언트 앱 설정&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Google I/O 2023에서 Firebase의 주요 소식을 확인하세요. 자세히 알아보기 의견 보내기 Android에서 Firebase 클라우드 메시징 클라이언트 앱 설정 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;firebase.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>질문 정리</category>
      <category>Android</category>
      <category>FCM</category>
      <category>Firebase Cloud Messaging</category>
      <category>newtoken</category>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/65</guid>
      <comments>https://like-while.tistory.com/65#entry65comment</comments>
      <pubDate>Wed, 28 Aug 2024 15:45:37 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 앱 난독화 알아보기</title>
      <link>https://like-while.tistory.com/64</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀 개발자분이 회사 안드로이드 앱이 난독화가 필요할 것 같다고 하셔서, 준비를 하게 되었습니다. 이전에 했던 개인 프로젝트들을 스토어에 올릴 때, abb 파일을 올리면 Progard 혹은 R8을 사용해서 난독화된 코드를 사용하라는 경고 메세지를 본 적이 있습니다. 이번 기회에 앱 난독화는 왜 해야하는지, 어떻게 하는 것인지 정리하려고 합니다.&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;난독화는 코드의 가독성을 떨어뜨려, 소스 코드를 분석하거나 역공학하는 것을 어렵게 만드는 기법입니다. 난독화를 통해 코드의 변수명, 메서드명, 클래스명을 의미 없는 문자열로 변환하거나, 코드의 구조를 복잡하게 만들어서 코드를 읽기 어렵게 만듭니다. 이는 주로 소스 코드의 보안을 강화하고, 소스 코드의 무단 복제나 악의적인 사용을 방지하기 위해 사용됩니다.&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;R8 적용 시 장점&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;축소&lt;/b&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;b&gt;최적화&lt;/b&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;b&gt;난독화&lt;/b&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;b&gt;사후 검증&lt;/b&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;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;R8 적용 시 단점&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;디버깅의 어려움&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ProGuard가 코드를 난독화하면 메소드 이름과 변수가 변경됩니다. 이로 인해 크래시 로그가 읽기 어려워지고, 문제를 진단하거나 디버깅하는 것이 더 복잡해집니다. 이는 특히 외부 라이브러리나 프레임워크에서 발생하는 문제를 해결할 때 더욱 도전적일 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;설정의 복잡성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ProGuard를 효과적으로 사용하려면 세심한 설정이 필요합니다. 잘못된 설정은 앱의 정상적인 기능을 방해할 수 있으며, 중요한 클래스나 메소드가 난독화 과정에서 제외되지 않아야 하는 경우 이를 정확히 지정해야 합니다. 설정을 잘못하면 런타임 오류가 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빌드 시간 증가&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ProGuard를 프로젝트에 적용하면, 난독화, 최적화, 그리고 축소 과정이 추가되어 앱의 빌드 시간이 길어질 수 있습니다. 이는 개발 과정에서 시간이 더 많이 소요될 수 있음을 의미합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;R8 사용법&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;R8 활성화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;R8은 안드로이드 build.gradle 버전 3.4.0 이상에서 기본적으로 활성화되어 있습니다. 별도로 활성화할 필요는 없으며, build.gradle 파일에 필요한 설정을 추가하면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ProGuard 설정 파일 구성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ProGuard 설정 파일 (proguard-rules.pro)을 사용하여 R8의 동작을 제어합니다.&lt;/li&gt;
&lt;li&gt;이 파일에서 난독화, 축소, 최적화와 관련된 규칙을 정의합니다. 예를 들어:&lt;/li&gt;
&lt;li&gt;-keep class com.example.myapp.** { *; } -dontwarn com.example.myapp.**&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빌드 파일 설정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;build.gradle 파일에서 릴리즈 빌드 구성에 R8을 사용하도록 설정합니다. R8은 기본적으로 활성화되어 있으므로, ProGuard 파일을 지정하기만 하면 됩니다:&lt;/li&gt;
&lt;li&gt;buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } }&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빌드 및 배포&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;R8 설정이 완료되면 애플리케이션을 빌드할 때 자동으로 R8이 실행되어 코드가 축소, 최적화 및 난독화됩니다.&lt;/li&gt;
&lt;li&gt;릴리즈 빌드를 실행하려면 다음 명령어를 사용할 수 있습니다:&lt;/li&gt;
&lt;li&gt;./gradlew assembleRelease&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;&lt;b&gt;1. 클래스, 메서드 및 필드 유지&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 클래스, 메서드 또는 필드를 난독화 및 제거하지 않도록 유지할 수 있습니다. 이는 주로 반사(reflection)를 사용하는 경우, 또는 특정 API를 외부에서 호출하는 경우에 필요합니다.&lt;/p&gt;
&lt;pre class=&quot;monkey&quot;&gt;&lt;code&gt;# 모든 공용 클래스와 메서드를 유지합니다.
-keep public class * {
    public *;
}

# 특정 패키지의 모든 클래스와 메서드를 유지합니다.
-keep class com.example.myapp.** { *; }

# 특정 클래스의 이름을 유지합니다.
-keepnames class com.example.myapp.MyClass
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 경고 무시&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ProGuard는 코드 축소 및 최적화 중 경고를 발생시킬 수 있습니다. 이러한 경고를 무시하도록 설정할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;# 특정 패키지의 경고를 무시합니다.
-dontwarn com.example.myapp.**
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 코드 축소 방지&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 클래스나 메서드를 제거하지 않도록 설정할 수 있습니다. 이는 주로 외부 라이브러리와의 호환성을 유지하기 위해 사용됩니다.&lt;/p&gt;
&lt;pre class=&quot;monkey&quot;&gt;&lt;code&gt;# 모든 애노테이션을 유지합니다.
-keep @interface **

# 특정 클래스의 모든 메서드를 유지합니다.
-keepclassmembers class com.example.myapp.MyClass {
    *;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 라이브러리 모드 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ProGuard를 라이브러리 모드로 설정하여, 프로젝트가 아닌 라이브러리의 코드를 난독화할 때 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;# 라이브러리 모드 활성화합니다.
-libraryjars /path/to/retrofit.jar
-libraryjars /path/to/okhttp.jar
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*라이브러리 모드(Library Mode)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ProGuard가 라이브러리 코드를 처리할 때 사용하는 특별한 설정입니다. 이 모드는 라이브러리의 코드가 다른 애플리케이션에 의해 사용될 수 있음을 가정하고, 이를 고려하여 코드 축소 및 난독화를 수행합니다. 즉, 라이브러리 모드는 ProGuard가 &quot;이 코드는 다른 앱에서도 사용될 거야, 중요한 부분은 손대지 말고 잘 보호해줘&quot;라고 인식하게 만드는 설정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 인라인 및 코드 제거 제어&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ProGuard가 인라인 및 코드 제거를 수행하는 방식을 제어할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;ldif&quot;&gt;&lt;code&gt;# 인라인을 비활성화합니다.
-dontoptimize
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*인라인 최적화 (Inlining Optimization)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 최적화는 컴파일러가 성능 향상을 위해 메서드 호출을 메서드의 실제 코드로 대체하는 최적화 기법입니다. 즉, 작은 메서드의 호출을 제거하고 그 메서드의 본문을 호출 지점에 직접 삽입하는 과정입니다. 이를 통해 함수 호출의 오버헤드를 줄이고 실행 속도를 높일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# 서버 통신 관련 클래스와 인터페이스를 유지합니다.
-keep class com.example.app.data.model.** { *; }
-keep interface com.example.app.data.remote.ApiService.** { *; }

# 라이브러리와 관련된 클래스와 메서드를 유지합니다.
# Keep Compose runtime Composable functions
-keepclassmembers class * {
    @androidx.compose.runtime.Composable *;
}

-keepclasseswithmembers class * {
    @androidx.compose.runtime.Composable *;
}

# Keep Dagger Hilt classes and annotations
-keep class dagger.hilt.** { *; }

-keepclassmembers class * {
    @dagger.hilt.android.qualifiers.ApplicationContext *;
    @dagger.hilt.android.lifecycle.HiltViewModel *;
}

# Keep Retrofit classes and annotations
-keep class retrofit2.** { *; }

# Keep attributes for Retrofit
-keepattributes Signature, Exceptions, RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations

-keepclasseswithmembers class * {
    @retrofit2.http.* &amp;lt;methods&amp;gt;;
}

# Keep Firebase and Google Play Services classes
-keep class com.google.firebase.** { *; }
-keep class com.google.android.gms.** { *; }

# Keep OkHttp Callback interface
-keep class okhttp3.Callback { *; }

# Keep AndroidX Lifecycle classes
-keep class androidx.lifecycle.ViewModel { *; }
-keep class androidx.lifecycle.LiveData { *; }

# Keep all classes extending Fragment
-keep class * extends androidx.fragment.app.Fragment { *; }

# Keep Gson classes and annotations
-keep class com.google.gson.** { *; }

-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.TypeAdapter
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

-keepclassmembers,allowobfuscation class * {
    @com.google.gson.annotations.SerializedName &amp;lt;fields&amp;gt;;
}

# Keep Kotlin coroutines methods
-keepclassmembers class kotlinx.coroutines.** {
    public &amp;lt;methods&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;발생할 수 있는 오류 리스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Missing classes detected while running R8.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 메시지에서 제공한 경로(C:\\...\\build\\outputs\\mapping\\debug\\missing_rules.txt)를 확인하여 어떤 클래스나 메소드가 누락되었는지 파악합니다. 추가적으로 필요한 keep 규칙이 있을 수 있습니다. 하지만 &lt;b&gt;OkHttp 4.11.0 버전 이전이라면, 라이브러리 오류일 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/square/okhttp/issues/6258&quot;&gt;https://github.com/square/okhttp/issues/6258&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721094894301&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Proguard Rules (OkHttp 4.7.2) &amp;middot; Issue #6258 &amp;middot; square/okhttp&quot; data-og-description=&quot;Hi, I am getting a few warnings when building with DexGuard. Gradle: 5.6.4 Android Gradle Plugin: 3.6.3 OkHttp: 4.7.2 compile_sdk = 30 build_tools = &amp;quot;30.0.2&amp;quot; Current Proguard rules for OkHttp: # ==...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/square/okhttp/issues/6258&quot; data-og-url=&quot;https://github.com/square/okhttp/issues/6258&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eq5X7j/hyWzwIkIcH/6G49WB5piymTFFXvlmlqL0/img.png?width=1200&amp;amp;height=600&amp;amp;face=990_118_1051_185&quot;&gt;&lt;a href=&quot;https://github.com/square/okhttp/issues/6258&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/square/okhttp/issues/6258&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eq5X7j/hyWzwIkIcH/6G49WB5piymTFFXvlmlqL0/img.png?width=1200&amp;amp;height=600&amp;amp;face=990_118_1051_185');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Proguard Rules (OkHttp 4.7.2) &amp;middot; Issue #6258 &amp;middot; square/okhttp&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Hi, I am getting a few warnings when building with DexGuard. Gradle: 5.6.4 Android Gradle Plugin: 3.6.3 OkHttp: 4.7.2 compile_sdk = 30 build_tools = &quot;30.0.2&quot; Current Proguard rules for OkHttp: # ==...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 빌드는 되는데, 서버 통신이 안되는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청까지는 잘 하는지 리턴으로 200이 돌아오는데 제가 만든 데이터 클래스를 사용하는 부분에서 못찾는 문제가 있었습니다. 데이터 클래스 또는 모델이 제대로 보존되지 않은 경우, Gson을 사용하여 JSON을 파싱할 때 필드 이름이 변경되어 올바르게 매핑되지 않을 수 있는 것 같습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;-keep class com.example.app.data.model.** { *; }
-keep interface com.example.app.data.remote.ApiService.** { *; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. e$default: java.lang.ClassCastException이 발생하는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ClassCastException은 타입 캐스팅 문제이므로, 관련 클래스의 타입 정보가 제대로 보존되도록 ProGuard 규칙을 조정해야 합니다. Gson은 내부적으로 리플렉션을 사용하여 객체를 생성하고 데이터를 할당합니다. 리플렉션을 사용하는 경우, 클래스의 생성자, 메소드, 필드가 난독화 과정에서 이름이 변경되거나 제거되지 않도록 보존해야 합니다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;-keepclassmembers class * {
    &amp;lt;init&amp;gt;(...);
    private &amp;lt;fields&amp;gt;;
    private &amp;lt;methods&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. AGP가 8.0보다 높은 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8.0부터는 R8이 프로가드와 호환모드가 아닌 풀모드로 동작하기 때문에 규칙을 더 자세히 작성해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/build/releases/gradle-plugin#default-changes&quot;&gt;https://developer.android.com/build/releases/gradle-plugin#default-changes&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721094935873&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Android Gradle 플러그인 8.5 출시 노트 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;Android 스튜디오 빌드 시스템은 Gradle을 기반으로 하며 Android Gradle 플러그인에는 Android 앱을 빌드하는 데 사용하는 몇 가지 추가 기능이 있습니다.&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/build/releases/gradle-plugin#default-changes&quot; data-og-url=&quot;https://developer.android.com/build/releases/gradle-plugin?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/3A28V/hyWCFjlaXd/0zj3KdCNriDfEDN40FQZAk/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/build/releases/gradle-plugin#default-changes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/build/releases/gradle-plugin#default-changes&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/3A28V/hyWCFjlaXd/0zj3KdCNriDfEDN40FQZAk/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Android Gradle 플러그인 8.5 출시 노트 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Android 스튜디오 빌드 시스템은 Gradle을 기반으로 하며 Android Gradle 플러그인에는 Android 앱을 빌드하는 데 사용하는 몇 가지 추가 기능이 있습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;&lt;a href=&quot;https://developer.android.com/build/shrink-code?hl=ko&quot;&gt;앱 축소, 난독화 및 최적화 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1720917915250&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;앱 축소, 난독화 및 최적화 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;사용하지 않는 코드와 리소스를 삭제하기 위해 출시 빌드에서 코드를 축소하는 방법을 알아보세요.&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/build/shrink-code?hl=ko&quot; data-og-url=&quot;https://developer.android.com/build/shrink-code?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bgNzo7/hyWzsFojDS/6FIFRkSeLl3kpMk3CwoeR0/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676,https://scrap.kakaocdn.net/dn/AXr0G/hyWzBoMZj4/jQhpkaq2HxCHTKp8QQwBOK/img.png?width=1708&amp;amp;height=1248&amp;amp;face=0_0_1708_1248&quot;&gt;&lt;a href=&quot;https://developer.android.com/build/shrink-code?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/build/shrink-code?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bgNzo7/hyWzsFojDS/6FIFRkSeLl3kpMk3CwoeR0/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676,https://scrap.kakaocdn.net/dn/AXr0G/hyWzBoMZj4/jQhpkaq2HxCHTKp8QQwBOK/img.png?width=1708&amp;amp;height=1248&amp;amp;face=0_0_1708_1248');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;앱 축소, 난독화 및 최적화 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;사용하지 않는 코드와 리소스를 삭제하기 위해 출시 빌드에서 코드를 축소하는 방법을 알아보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/build/kotlin-support?hl=ko&quot;&gt;Kotlin 버전에 필요한 D8 및 R8 컴파일러 버전 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1720917923460&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Kotlin 버전에 필요한 D8 및 R8 컴파일러 버전 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;각 Kotlin 버전의 최소 D8/R8 버전을 찾습니다.&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/build/kotlin-support?hl=ko&quot; data-og-url=&quot;https://developer.android.com/build/kotlin-support?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/0hm8A/hyWzv3bZsn/Ky6xgT1GKdWKrHrNfRcBH0/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/build/kotlin-support?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/build/kotlin-support?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/0hm8A/hyWzv3bZsn/Ky6xgT1GKdWKrHrNfRcBH0/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kotlin 버전에 필요한 D8 및 R8 컴파일러 버전 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;각 Kotlin 버전의 최소 D8/R8 버전을 찾습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>질문 정리</category>
      <category>Android</category>
      <category>프로가드</category>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/64</guid>
      <comments>https://like-while.tistory.com/64#entry64comment</comments>
      <pubDate>Sun, 14 Jul 2024 09:46:05 +0900</pubDate>
    </item>
    <item>
      <title>[Dagger/MissingBinding] UserData cannot be provided without an @Provides-annotated method.</title>
      <link>https://like-while.tistory.com/63</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dagger에서 발생하는 MissingBinding 오류는 종속성 주입 과정에서 필요한 객체를 제공할 방법이 없을 때 나타납니다. 이 경우 UserData 객체에 대한 의존성을 해결하기 위해 적절한 제공 메커니즘을 설정해야 합니다. UserData가 객체로 정의되어 있기 때문에, 이 객체의 인스턴스를 주입할 수 있도록 Dagger 설정을 추가해야 합니다.&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;UserData 제공 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UserData는 이미 object로 선언되어 있으므로, Dagger 모듈에서 이를 직접 제공하는 방법으로 접근할 수 있습니다.UserData를 Dagger 컨테이너에 등록하여 다른 컴포넌트에서 UserData를 주입받을 수 있도록 설정합니다. 이를 위해 @Provides와 @Singleton 어노테이션을 사용하여 UserData 객체를 제공하는 메서드를 만들어야 합니다.&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;@Provides의 의미&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Provides 어노테이션은 Dagger에게 특정 객체를 생성하거나 제공하는 방법을 명시하는 데 사용됩니다. 즉, Dagger가 종속성 그래프에서 필요한 객체를 어떻게 생성하고 제공해야 하는지 알려주는 역할을 합니다. 이 어노테이션은 모듈 클래스의 메서드에 사용되며, 해당 메서드가 반환하는 객체를 Dagger가 관리하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 다음과 같이 @Provides 어노테이션이 사용된 메서드를 정의하면, Dagger는 이 메서드를 호출하여 UserData 객체를 제공할 수 있습니다&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Provides
fun provideUserData(): UserData {
    return UserData
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;수정된 AppModule&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;UserData 제공 설정&lt;/b&gt;: UserData 객체를 Dagger 모듈에서 제공하도록 설정합니다. UserData는 object로 선언되어 있으므로 싱글턴 인스턴스를 제공하기 위해 @Singleton과 @Provides 어노테이션을 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TokenAuthenticator 제공 설정&lt;/b&gt;: TokenAuthenticator 클래스는 ApiService와 UserData를 필요로 합니다. 이를 Dagger 모듈에서 @Provides 메서드를 통해 제공하며, UserData 인스턴스를 주입받도록 설정합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Singleton
    @Provides
    fun provideUserData(): UserData {
        return UserData
    }
    
    @Provides
    fun provideTokenAuthenticator(apiServiceProvider: Provider&amp;lt;ApiService&amp;gt;, userData: UserData): TokenAuthenticator {
        return TokenAuthenticator(apiServiceProvider, userData)
    }
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>질문 정리</category>
      <category>@provides</category>
      <category>dagger</category>
      <category>hilt</category>
      <category>missingbinding</category>
      <author>five weeks</author>
      <guid isPermaLink="true">https://like-while.tistory.com/63</guid>
      <comments>https://like-while.tistory.com/63#entry63comment</comments>
      <pubDate>Sat, 13 Jul 2024 08:06:18 +0900</pubDate>
    </item>
  </channel>
</rss>