<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>[ssuper 성.게군]</title>
    <link>https://sojw.tistory.com/</link>
    <description>좌충우돌. 으헤헤헤.</description>
    <language>ko</language>
    <pubDate>Tue, 9 Jun 2026 19:31:00 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>성게군.</managingEditor>
    <image>
      <title>[ssuper 성.게군]</title>
      <url>https://t1.daumcdn.net/cfile/tistory/2350264A5371E10A06</url>
      <link>https://sojw.tistory.com</link>
    </image>
    <item>
      <title>Swagger UI 운영환경 노출 위험에 대한 기술 가이드</title>
      <link>https://sojw.tistory.com/1169742130</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI는 API 명세와 테스트 기능을 제공하여 개발 단계에서는 매우 유용하다.&lt;br /&gt;그러나 운영환경(Production)에 노출될 경우, 단순한 문서 노출 수준을 넘어&lt;br /&gt;&lt;b&gt;시스템 내부 구조와 실행 기능이 외부 공격자에게 통째로 제공되는 심각한 보안 리스크&lt;/b&gt;를 초래한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI는&lt;/p&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;API 호출 기능(Try It Out)&lt;/li&gt;
&lt;li&gt;UI 자체 취약점 가능성&lt;br /&gt;을 모두 포함하는 복합적 공격 지점이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서는 Swagger UI 운영환경 노출이 왜 위험한지, 어떤 공격이 가능한지,&lt;br /&gt;그리고 조직에서 어떤 정책을 가져야 하는지 이해하기 쉽게 설명한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Swagger UI 운영환경 노출이 왜 위험한가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI 노출은 아래 네 가지 문제를 동시에 발생시키며,&lt;br /&gt;각 문제는 서로 연결되어 전체 공격 표면을 기하급수적으로 확장시킨다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 API 구조 전체 노출&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI는 API 문서 이상의 기능을 제공한다.&lt;br /&gt;운영환경에 노출되면 다음 정보가 외부에 공개된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전체 엔드포인트 목록&lt;/li&gt;
&lt;li&gt;요청 파라미터 및 검증 규칙&lt;/li&gt;
&lt;li&gt;응답 모델과 데이터 구조&lt;/li&gt;
&lt;li&gt;인증 필요 여부&lt;/li&gt;
&lt;li&gt;내부용/관리자용 API 포함 여부&lt;/li&gt;
&lt;li&gt;에러 메시지 및 동작 패턴&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 정보는 공격자가 내부 API를 역설계하지 않고도 공격 전략을 수립하도록 돕는다.&lt;br /&gt;즉, &lt;b&gt;블랙박스 공격 &amp;rarr; 화이트박스 공격으로 변환&lt;/b&gt;된다.&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;StackOverflow &amp;ndash; &lt;a href=&quot;https://stackoverflow.com/questions/62201695/best-practices-for-swagger-ui-in-production&quot;&gt;https://stackoverflow.com/questions/62201695/best-practices-for-swagger-ui-in-production&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 &amp;ldquo;Try It Out&amp;rdquo; 기능을 통한 실제 운영 데이터 접근&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI는 단순한 문서가 아니라,&lt;br /&gt;&lt;b&gt;운영 API를 직접 호출할 수 있는 실행 도구&lt;/b&gt;다.&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;인증이 느슨한 API 반복 호출 &amp;rarr; DoS 상황 발생&lt;/li&gt;
&lt;li&gt;관리자/정산/배치 등 내부용 API 호출&lt;/li&gt;
&lt;li&gt;시스템 상태를 파악하기 위한 probing&lt;/li&gt;
&lt;/ul&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;Codidact &amp;ndash; &lt;a href=&quot;https://software.codidact.com/posts/290498&quot;&gt;https://software.codidact.com/posts/290498&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 인증&amp;middot;인가 우회 가능성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발환경에서 Swagger를 편하게 사용하기 위해&lt;br /&gt;아래 같은 설정이 종종 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Swagger UI는 인증 없이 접근 가능&lt;/li&gt;
&lt;li&gt;일부 API에 인증 건너뛰기 옵션 존재&lt;/li&gt;
&lt;li&gt;Try It Out 요청 시 인증 헤더 자동 삽입&lt;/li&gt;
&lt;li&gt;내부용 API도 문서에 표시&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 설정이 운영까지 그대로 배포되면,&lt;br /&gt;&lt;b&gt;인증이 필요한 API도 인증 없이 호출 가능한 보안 사고&lt;/b&gt;가 발생한다.&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;Medium &amp;ndash; &lt;a href=&quot;https://r0x5r.medium.com/the-hidden-risk-of-swagger-ui-a-real-world-case-of-unauthorized-access-790ea9bdb033&quot;&gt;https://r0x5r.medium.com/the-hidden-risk-of-swagger-ui-a-real-world-case-of-unauthorized-access-790ea9bdb033&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4 Swagger UI 자체 취약점 악용 가능성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI는 UI 레벨에서도 보안 취약점이 보고된 바 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XSS (스크립트 실행)&lt;/li&gt;
&lt;li&gt;HTML Injection&lt;/li&gt;
&lt;li&gt;쿼리 파라미터 조작 기반 공격&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영환경에 Swagger UI가 노출될 경우&lt;br /&gt;&lt;b&gt;브라우저 측 공격(토큰 탈취, 세션 하이재킹)&lt;/b&gt; 의 통로가 된다.&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;InfoSec Writeups &amp;ndash;&lt;br /&gt;&lt;a href=&quot;https://infosecwriteups.com/the-dark-side-of-swagger-ui-how-xss-and-html-injection-can-compromise-apis-1b670972a443&quot;&gt;https://infosecwriteups.com/the-dark-side-of-swagger-ui-how-xss-and-html-injection-can-compromise-apis-1b670972a443&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 공격 시나리오 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI가 운영환경에 노출되었을 때 실제로 가능한 전형적 공격 흐름은 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;공격자가 &lt;code&gt;/swagger-ui&lt;/code&gt; 또는 &lt;code&gt;/v3/api-docs&lt;/code&gt;에 접근&lt;/li&gt;
&lt;li&gt;내부&amp;middot;관리자&amp;middot;정산 API 등 민감 엔드포인트 확인&lt;/li&gt;
&lt;li&gt;인증이 없는 API 또는 인증 취약점 탐색&lt;/li&gt;
&lt;li&gt;Try It Out 기능으로 실제 운영 데이터 호출&lt;/li&gt;
&lt;li&gt;파라미터 변조, 권한 우회, 대량 요청 등 공격 수행&lt;/li&gt;
&lt;li&gt;결과: 데이터 오염, 서비스 중단, 권한 침해, 내부 정보 유출&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 운영환경에서의 관리 원칙&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 기본 원칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영환경에서는 Swagger UI 및 api-docs는 &lt;b&gt;기본적으로 비활성화&lt;/b&gt;한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 예외 허용 기준&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부득이한 경우 아래 조건 &lt;b&gt;모두 충족 시 제한적 허용&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;VPN/사내망/IP 화이트리스트 기반 접근 제한&lt;/li&gt;
&lt;li&gt;별도 인증(Basic Auth, OAuth 등) 적용&lt;/li&gt;
&lt;li&gt;비표준 Swagger 경로 사용 (/swagger &amp;rarr; /internal-docs 등)&lt;/li&gt;
&lt;li&gt;Try It Out 기능 비활성화 고려&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Baeldung &amp;ndash; &lt;a href=&quot;https://www.baeldung.com/swagger-ui-turn-off-in-production&quot;&gt;https://www.baeldung.com/swagger-ui-turn-off-in-production&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI는 개발환경에서는 생산성을 높이는 도구이지만,&lt;br /&gt;운영환경에서는 &amp;ldquo;API 문서 + API 실행기 + 잠재적 취약점&amp;rdquo;을 외부에 제공하는 공격 표면이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영환경 Swagger 노출은&lt;br /&gt;&lt;b&gt;내부 설계서 + API 호출 도구 + 디버깅 콘솔을 공격자에게 무료로 제공하는 것&lt;/b&gt;과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;운영환경에서는 반드시 비활성화&lt;/b&gt; 하며,&lt;br /&gt;예외가 필요한 경우에도 강력한 접근 제어가 필수적이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;Appendix. Swagger UI 운영환경 노출 관련 다이어그램&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 Appendix는 본문 설명을 시각적으로 이해할 수 있도록&lt;br /&gt;&amp;ldquo;공격 흐름&amp;rdquo;과 &amp;ldquo;공격 표면 확장 구조&amp;rdquo;를 다이어그램으로 정리한 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;A-1. Attack Flow&lt;/h2&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;sequenceDiagram
    participant A as 공격자
    participant S as Swagger UI (운영환경)
    participant API as 내부 API 서버

    A-&amp;gt;&amp;gt;S: 운영환경 Swagger UI 접근 (/swagger-ui)
    S--&amp;gt;&amp;gt;A: API 엔드포인트&amp;middot;요청/응답 스키마 노출
    A-&amp;gt;&amp;gt;A: 민감/내부용 API 식별
    A-&amp;gt;&amp;gt;S: Try It Out으로 요청 생성
    S-&amp;gt;&amp;gt;API: 실제 운영 API 호출
    API--&amp;gt;&amp;gt;S: 실제 데이터/에러정보 반환
    S--&amp;gt;&amp;gt;A: 응답 노출
    A-&amp;gt;&amp;gt;API: 대량 호출&amp;middot;변조 공격 실행&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1958&quot; data-origin-height=&quot;1350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5nwIC/dJMcajtSoPw/KLRaTTnSLcNwUiufxeX62k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5nwIC/dJMcajtSoPw/KLRaTTnSLcNwUiufxeX62k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5nwIC/dJMcajtSoPw/KLRaTTnSLcNwUiufxeX62k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5nwIC%2FdJMcajtSoPw%2FKLRaTTnSLcNwUiufxeX62k%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;1958&quot; height=&quot;1350&quot; data-origin-width=&quot;1958&quot; data-origin-height=&quot;1350&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;A-2. Attack Surface&lt;/h2&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;graph TD

    A[운영환경 Swagger UI 노출] --&amp;gt; B[API 스펙&amp;middot;구조 전체 노출]
    A --&amp;gt; C[Try It Out 기능 활성화]
    A --&amp;gt; D[인증/인가 우회 가능성]
    A --&amp;gt; E[Swagger UI 자체 취약점 노출]

    B --&amp;gt; F[엔드포인트 수집]
    B --&amp;gt; G[파라미터 브루트포싱]
    C --&amp;gt; H[운영 데이터 변조]
    C --&amp;gt; I[대량 호출&amp;middot;서비스 부하]
    D --&amp;gt; J[내부용 API 접근]
    E --&amp;gt; K[XSS&amp;middot;브라우저 공격]

    F --&amp;gt; L[화이트박스 기반 공격]
    J --&amp;gt; M[권한 오용&amp;middot;정보 유출]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1958&quot; data-origin-height=&quot;1350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bndkcB/dJMcaiht5le/ZrL30M6QTXPWu23mdXK2p1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bndkcB/dJMcaiht5le/ZrL30M6QTXPWu23mdXK2p1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bndkcB/dJMcaiht5le/ZrL30M6QTXPWu23mdXK2p1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbndkcB%2FdJMcaiht5le%2FZrL30M6QTXPWu23mdXK2p1%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;1958&quot; height=&quot;1350&quot; data-origin-width=&quot;1958&quot; data-origin-height=&quot;1350&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;hr data-ke-style=&quot;style1&quot; /&gt;</description>
      <category>emotional developer/detect-Web</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742130</guid>
      <comments>https://sojw.tistory.com/1169742130#entry1169742130comment</comments>
      <pubDate>Sun, 30 Nov 2025 21:38:33 +0900</pubDate>
    </item>
    <item>
      <title>성수동 월정기 주차 신청 가이드 (2025년 6월)</title>
      <link>https://sojw.tistory.com/1169742129</link>
      <description>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;ko&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;성수동 월정기 주차 신청 가이드&lt;/title&gt;
    &lt;style&gt;
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
            line-height: 1.7;
            margin: 0;
            padding: 20px;
            background-color: #fafafa;
            color: #333;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.08);
            overflow: hidden;
        }
        .header {
            background: linear-gradient(135deg, #4a90e2 0%, #357abd 100%);
            color: white;
            padding: 40px 30px;
            text-align: center;
        }
        .header h1 {
            margin: 0 0 10px 0;
            font-size: 2.2em;
            font-weight: 600;
        }
        .header p {
            margin: 0;
            font-size: 1.1em;
            opacity: 0.9;
        }
        .content {
            padding: 40px 30px;
        }
        .intro {
            font-size: 1.1em;
            line-height: 1.8;
            margin-bottom: 40px;
            padding: 25px;
            background: #f8f9fc;
            border-radius: 8px;
            border-left: 4px solid #4a90e2;
        }
        .section {
            margin-bottom: 50px;
        }
        .section h2 {
            color: #2c3e50;
            font-size: 1.6em;
            margin-bottom: 25px;
            padding-bottom: 10px;
            border-bottom: 2px solid #4a90e2;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .section-number {
            background: #4a90e2;
            color: white;
            width: 30px;
            height: 30px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.9em;
        }
        .process-steps {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin: 30px 0;
        }
        .process-step {
            background: white;
            border: 1px solid #e1e5e9;
            border-radius: 8px;
            padding: 20px;
            text-align: center;
            position: relative;
        }
        .process-step h4 {
            color: #4a90e2;
            margin: 0 0 10px 0;
            font-size: 1.1em;
        }
        .process-step p {
            margin: 0;
            font-size: 0.9em;
            color: #666;
        }
        .step-icon {
            background: #4a90e2;
            color: white;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 0 auto 15px;
            font-size: 1.2em;
        }
        .detail-cards {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 20px;
            margin: 25px 0;
        }
        .detail-card {
            background: #f8f9fc;
            border: 1px solid #e1e5e9;
            border-radius: 8px;
            padding: 25px;
        }
        .detail-card h3 {
            color: #2c3e50;
            margin: 0 0 15px 0;
            font-size: 1.1em;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .detail-card p {
            margin: 8px 0;
            font-size: 0.95em;
        }
        .detail-card strong {
            color: #2c3e50;
        }
        .comparison-table {
            background: white;
            border: 1px solid #e1e5e9;
            border-radius: 8px;
            overflow: hidden;
            margin: 25px 0;
        }
        .comparison-table table {
            width: 100%;
            border-collapse: collapse;
        }
        .comparison-table th,
        .comparison-table td {
            padding: 15px;
            text-align: left;
            border-bottom: 1px solid #f0f0f0;
        }
        .comparison-table th {
            background: #4a90e2;
            color: white;
            font-weight: 600;
        }
        .comparison-table tr:nth-child(even) {
            background: #f8f9fc;
        }
        .price-box {
            background: #fff3cd;
            border: 1px solid #ffeaa7;
            border-radius: 6px;
            padding: 8px 12px;
            display: inline-block;
            font-weight: 600;
            color: #856404;
        }
        .highlight-box {
            background: #d1ecf1;
            border: 1px solid #bee5eb;
            border-radius: 6px;
            padding: 8px 12px;
            display: inline-block;
            font-weight: 600;
            color: #0c5460;
        }
        .info-box {
            background: #f8f9fc;
            border-left: 4px solid #4a90e2;
            padding: 20px 25px;
            margin: 20px 0;
            border-radius: 0 8px 8px 0;
        }
        .contact-section {
            background: #2c3e50;
            color: white;
            padding: 30px;
            border-radius: 8px;
            margin-top: 40px;
        }
        .contact-section h3 {
            margin: 0 0 20px 0;
            color: white;
        }
        .contact-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 25px;
        }
        .contact-item h4 {
            margin: 0 0 10px 0;
            color: #74b9ff;
        }
        .contact-item p {
            margin: 5px 0;
            font-size: 0.95em;
        }
        .tip-section {
            background: linear-gradient(135deg, #a8e6cf 0%, #88d8a3 100%);
            color: #2d5016;
            padding: 25px;
            border-radius: 8px;
            margin: 30px 0;
        }
        .tip-section h3 {
            margin: 0 0 15px 0;
            color: #2d5016;
        }
        ul {
            padding-left: 20px;
        }
        li {
            margin: 8px 0;
        }
        .parking-visual {
            background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
            border-radius: 8px;
            padding: 30px;
            text-align: center;
            margin: 25px 0;
            border: 1px solid #90caf9;
        }
        .parking-spots-demo {
            display: flex;
            justify-content: center;
            gap: 10px;
            margin: 20px 0;
            flex-wrap: wrap;
        }
        .parking-spot {
            width: 35px;
            height: 50px;
            border: 2px solid #4a90e2;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            background: white;
        }
        .parking-spot.occupied {
            background: #4a90e2;
            color: white;
        }
        .legend {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin-top: 15px;
            font-size: 0.9em;
        }
        .legend-item {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .legend-box {
            width: 20px;
            height: 20px;
            border: 2px solid #4a90e2;
            border-radius: 3px;
        }
        .legend-box.occupied {
            background: #4a90e2;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;container&quot;&gt;
        &lt;div class=&quot;header&quot;&gt;
            &lt;h1&gt;성수동 월정기 주차 신청 가이드&lt;/h1&gt;
            &lt;p&gt;공영주차장과 민간주차장 완벽 비교 분석&lt;/p&gt;
        &lt;/div&gt;
        
        &lt;div class=&quot;content&quot;&gt;
            &lt;div class=&quot;intro&quot;&gt;
                &lt;p&gt;성수동에서 월정기 주차를 신청하려면, 공영주차장과 민간 주차장을 각각 어떻게 이용할 수 있는지 알아보는 것이 중요합니다. 이 포스팅에서는 공영주차장과 민간 주차장 월정기 신청 절차와 각각의 장단점을 상세히 비교해드리겠습니다.&lt;/p&gt;
            &lt;/div&gt;

            &lt;div class=&quot;section&quot;&gt;
                &lt;h2&gt;&lt;span class=&quot;section-number&quot;&gt;1&lt;/span&gt;공영주차장 월정기 신청 절차&lt;/h2&gt;
                
                &lt;div class=&quot;process-steps&quot;&gt;
                    &lt;div class=&quot;process-step&quot;&gt;
                        &lt;div class=&quot;step-icon&quot;&gt; &lt;/div&gt;
                        &lt;h4&gt;회원가입 및 본인인증&lt;/h4&gt;
                        &lt;p&gt;성동구 도시관리공단 홈페이지에서 회원가입 후 본인인증 진행&lt;/p&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;process-step&quot;&gt;
                        &lt;div class=&quot;step-icon&quot;&gt; &lt;/div&gt;
                        &lt;h4&gt;배정기준 확인&lt;/h4&gt;
                        &lt;p&gt;거주기간, 대기기간 등 배점 기준 미리 확인&lt;/p&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;process-step&quot;&gt;
                        &lt;div class=&quot;step-icon&quot;&gt; &lt;/div&gt;
                        &lt;h4&gt;정기권 신청&lt;/h4&gt;
                        &lt;p&gt;매월 공고에 따라 선착순 또는 추첨으로 신청&lt;/p&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;process-step&quot;&gt;
                        &lt;div class=&quot;step-icon&quot;&gt; &lt;/div&gt;
                        &lt;h4&gt;결제 및 이용시작&lt;/h4&gt;
                        &lt;p&gt;1개월 선납 결제 후 바로 이용 가능&lt;/p&gt;
                    &lt;/div&gt;
                &lt;/div&gt;

                &lt;div class=&quot;detail-cards&quot;&gt;
                    &lt;div class=&quot;detail-card&quot;&gt;
                        &lt;h3&gt;  신청 방법&lt;/h3&gt;
                        &lt;p&gt;&lt;strong&gt;사이트:&lt;/strong&gt; &lt;a href=&quot;https://parking.happysd.or.kr/&quot; target=&quot;_blank&quot; style=&quot;color: #4a90e2;&quot;&gt;성동구 도시관리공단 홈페이지&lt;/a&gt;&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;회원가입:&lt;/strong&gt; &lt;a href=&quot;https://parking.happysd.or.kr/Account/JoinStep01_00&quot; target=&quot;_blank&quot; style=&quot;color: #4a90e2;&quot;&gt;회원가입 바로가기&lt;/a&gt;&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;필요 서류:&lt;/strong&gt; 주민등록증, 차량 등록증&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;주요 사항:&lt;/strong&gt; 온라인 서비스에서 회원가입 후 본인 인증을 거쳐 차량 정보를 등록합니다.&lt;/p&gt;
                    &lt;/div&gt;
                    
                    &lt;div class=&quot;detail-card&quot;&gt;
                        &lt;h3&gt;  배정 기준 확인&lt;/h3&gt;
                        &lt;p&gt;&lt;strong&gt;배점 기준:&lt;/strong&gt; 성동구 거주 기간, 대기 기간 등&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 장애인, 국가유공자 등의 특혜 대상&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;배정경쟁률:&lt;/strong&gt; &lt;a href=&quot;https://parking.happysd.or.kr/Public/GuideBesidesRoadTab1&quot; target=&quot;_blank&quot; style=&quot;color: #4a90e2;&quot;&gt;실시간 경쟁률 확인&lt;/a&gt;&lt;/p&gt;
                    &lt;/div&gt;
                    
                    &lt;div class=&quot;detail-card&quot;&gt;
                        &lt;h3&gt;  정기권 신청&lt;/h3&gt;
                        &lt;p&gt;매월 정기권 신청 공고에 따라 신청 가능&lt;/p&gt;
                        &lt;p&gt;선착순 또는 추첨 방식으로 진행&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;신청 사이트:&lt;/strong&gt; &lt;a href=&quot;https://www.sisul.or.kr/open_content/parking/commuter/application.jsp&quot; target=&quot;_blank&quot; style=&quot;color: #4a90e2;&quot;&gt;서울시설공단 정기권 신청&lt;/a&gt;&lt;/p&gt;
                    &lt;/div&gt;
                    
                    &lt;div class=&quot;detail-card&quot;&gt;
                        &lt;h3&gt;  결제 및 이용&lt;/h3&gt;
                        &lt;p&gt;&lt;strong&gt;결제 방식:&lt;/strong&gt; 1개월 선납&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;이용 기간:&lt;/strong&gt; 매월 1일부터 말일까지 이용 가능&lt;/p&gt;
                    &lt;/div&gt;
                &lt;/div&gt;

                &lt;div class=&quot;info-box&quot;&gt;
                    &lt;h4&gt;  환불 및 취소 정책&lt;/h4&gt;
                    &lt;p&gt;중도 해지 시 잔여 기간 80% 환불 가능하며, 감면 적용 후 소급 환불은 불가합니다.&lt;/p&gt;
                    &lt;p&gt;&lt;strong&gt;할인 혜택:&lt;/strong&gt;&lt;/p&gt;
                    &lt;ul style=&quot;margin: 10px 0; padding-left: 20px;&quot;&gt;
                        &lt;li&gt;&lt;strong&gt;80% 할인:&lt;/strong&gt; 장애인, 국가유공상이자, 고엽제후유증환자&lt;/li&gt;
                        &lt;li&gt;&lt;strong&gt;50% 할인:&lt;/strong&gt; 경차(1,000cc 미만), 저공해차량, 5.18민주유공자, 다둥이카드(3자녀 이상)&lt;/li&gt;
                        &lt;li&gt;&lt;strong&gt;30% 할인:&lt;/strong&gt; 다둥이카드(2자녀)&lt;/li&gt;
                    &lt;/ul&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;section&quot;&gt;
                &lt;h2&gt;&lt;span class=&quot;section-number&quot;&gt;2&lt;/span&gt;민간 주차장 월정기 신청&lt;/h2&gt;
                
                &lt;div class=&quot;parking-visual&quot;&gt;
                    &lt;h4&gt;성수동 민간 주차장 현황&lt;/h4&gt;
                    &lt;div class=&quot;parking-spots-demo&quot;&gt;
                        &lt;div class=&quot;parking-spot&quot;&gt; &lt;/div&gt;
                        &lt;div class=&quot;parking-spot occupied&quot;&gt; &lt;/div&gt;
                        &lt;div class=&quot;parking-spot&quot;&gt; &lt;/div&gt;
                        &lt;div class=&quot;parking-spot occupied&quot;&gt; &lt;/div&gt;
                        &lt;div class=&quot;parking-spot&quot;&gt; &lt;/div&gt;
                        &lt;div class=&quot;parking-spot occupied&quot;&gt; &lt;/div&gt;
                        &lt;div class=&quot;parking-spot&quot;&gt; &lt;/div&gt;
                        &lt;div class=&quot;parking-spot occupied&quot;&gt; &lt;/div&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;legend&quot;&gt;
                        &lt;div class=&quot;legend-item&quot;&gt;
                            &lt;div class=&quot;legend-box&quot;&gt;&lt;/div&gt;
                            &lt;span&gt;이용 가능&lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class=&quot;legend-item&quot;&gt;
                            &lt;div class=&quot;legend-box occupied&quot;&gt;&lt;/div&gt;
                            &lt;span&gt;이용 중&lt;/span&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
                
                &lt;p style=&quot;margin-bottom: 30px;&quot;&gt;민간 주차장은 성수동 일대에서도 이용 가능하며, 주차 요금은 공영주차장보다 다소 높을 수 있습니다. 하지만 일부 민간 주차장에서는 공영주차장보다 더 유연한 시간대와 장소에서 월정기를 신청할 수 있는 장점이 있습니다.&lt;/p&gt;

                &lt;h3&gt;  주요 민간 주차장 현황&lt;/h3&gt;
                &lt;div class=&quot;detail-cards&quot;&gt;
                    &lt;div class=&quot;detail-card&quot;&gt;
                        &lt;h3&gt;  성수역 인근 자주식 주차장&lt;/h3&gt;
                        &lt;p&gt;&lt;span class=&quot;price-box&quot;&gt;월정기 요금: 약 400,000원&lt;/span&gt;&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;주차 방식:&lt;/strong&gt; 자주식 주차&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;위치:&lt;/strong&gt; 성수역 인근&lt;/p&gt;
                    &lt;/div&gt;
                    
                    &lt;div class=&quot;detail-card&quot;&gt;
                        &lt;h3&gt;  모두의 주차장 앱 제휴&lt;/h3&gt;
                        &lt;p&gt;&lt;span class=&quot;price-box&quot;&gt;월정기 요금: 100,000원~200,000원&lt;/span&gt;&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;위치:&lt;/strong&gt; 서울숲 디타워, 갤러리아포레더몰&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;주차 방식:&lt;/strong&gt; 기계식 및 자주식&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;앱 다운로드:&lt;/strong&gt; 
                            &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.parkingshare.mobile&quot; target=&quot;_blank&quot; style=&quot;color: #4a90e2;&quot;&gt;Android&lt;/a&gt; | 
                            &lt;a href=&quot;https://apps.apple.com/kr/app/모두의주차장&quot; target=&quot;_blank&quot; style=&quot;color: #4a90e2;&quot;&gt;iOS&lt;/a&gt;
                        &lt;/p&gt;
                    &lt;/div&gt;
                    
                    &lt;div class=&quot;detail-card&quot;&gt;
                        &lt;h3&gt;  성수빌딩 주차장&lt;/h3&gt;
                        &lt;p&gt;&lt;span class=&quot;price-box&quot;&gt;월정기 요금: 100,000원~200,000원&lt;/span&gt;&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;특징:&lt;/strong&gt; 건물별 개별 문의 필요&lt;/p&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;section&quot;&gt;
                &lt;h2&gt;&lt;span class=&quot;section-number&quot;&gt;3&lt;/span&gt;공영주차장 vs 민간주차장 비교&lt;/h2&gt;
                
                &lt;div class=&quot;comparison-table&quot;&gt;
                    &lt;table&gt;
                        &lt;thead&gt;
                            &lt;tr&gt;
                                &lt;th&gt;비교 항목&lt;/th&gt;
                                &lt;th&gt;공영주차장&lt;/th&gt;
                                &lt;th&gt;민간주차장&lt;/th&gt;
                            &lt;/tr&gt;
                        &lt;/thead&gt;
                        &lt;tbody&gt;
                            &lt;tr&gt;
                                &lt;td&gt;&lt;strong&gt;신청 절차&lt;/strong&gt;&lt;/td&gt;
                                &lt;td&gt;온라인/대면 신청, 배점 및 추첨 기준&lt;/td&gt;
                                &lt;td&gt;현장 등록, 문의 후 신청&lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;td&gt;&lt;strong&gt;월정기 요금&lt;/strong&gt;&lt;/td&gt;
                                &lt;td&gt;&lt;span class=&quot;highlight-box&quot;&gt;약 70,000원&lt;/span&gt;&lt;/td&gt;
                                &lt;td&gt;&lt;span class=&quot;price-box&quot;&gt;100,000원~400,000원&lt;/span&gt;&lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;td&gt;&lt;strong&gt;할인 혜택&lt;/strong&gt;&lt;/td&gt;
                                &lt;td&gt;장애인, 저공해차량 등 할인 적용&lt;/td&gt;
                                &lt;td&gt;일부 업체에서 자체 할인 적용 가능&lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;td&gt;&lt;strong&gt;경쟁률&lt;/strong&gt;&lt;/td&gt;
                                &lt;td&gt;높음 (선착순/추첨)&lt;/td&gt;
                                &lt;td&gt;상대적으로 낮음&lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;td&gt;&lt;strong&gt;이용 편의성&lt;/strong&gt;&lt;/td&gt;
                                &lt;td&gt;제한적&lt;/td&gt;
                                &lt;td&gt;상대적으로 유연함&lt;/td&gt;
                            &lt;/tr&gt;
                        &lt;/tbody&gt;
                    &lt;/table&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;section&quot;&gt;
                &lt;h2&gt;&lt;span class=&quot;section-number&quot;&gt;4&lt;/span&gt;민간주차장 월정기 이용 가능 현황&lt;/h2&gt;
                &lt;div class=&quot;info-box&quot;&gt;
                    &lt;p&gt;&lt;strong&gt;최소 확인된 곳:&lt;/strong&gt; 1곳 이상&lt;/p&gt;
                    &lt;p&gt;&lt;strong&gt;예상 가능한 주차장:&lt;/strong&gt; 3~5곳 (주차장 앱, 커뮤니티, 현장 문의를 통해 확인 필요)&lt;/p&gt;
                    &lt;p&gt;&lt;strong&gt;참고사항:&lt;/strong&gt; 성수동 일대의 민간주차장은 건물별로 운영 정책이 다르므로 개별 문의가 필요합니다.&lt;/p&gt;
                    &lt;p&gt;&lt;strong&gt;유용한 사이트:&lt;/strong&gt;&lt;/p&gt;
                    &lt;ul style=&quot;margin: 10px 0; padding-left: 20px;&quot;&gt;
                        &lt;li&gt;&lt;a href=&quot;https://www.moduparking.com/&quot; target=&quot;_blank&quot; style=&quot;color: #4a90e2;&quot;&gt;모두의주차장 웹사이트&lt;/a&gt; - 월정기권 검색&lt;/li&gt;
                        &lt;li&gt;&lt;a href=&quot;https://app.modu.kr/map&quot; target=&quot;_blank&quot; style=&quot;color: #4a90e2;&quot;&gt;모두의주차장 지도&lt;/a&gt; - 성수동 주변 주차장 검색&lt;/li&gt;
                        &lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.skt.tmap.ku&quot; target=&quot;_blank&quot; style=&quot;color: #4a90e2;&quot;&gt;TMAP 앱&lt;/a&gt; - 통합 모빌리티 플랫폼&lt;/li&gt;
                    &lt;/ul&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;section&quot;&gt;
                &lt;h2&gt;&lt;span class=&quot;section-number&quot;&gt;5&lt;/span&gt;성공적인 주차장 신청을 위한 팁&lt;/h2&gt;
                
                &lt;div class=&quot;tip-section&quot;&gt;
                    &lt;h3&gt;  알아두면 유용한 팁&lt;/h3&gt;
                    &lt;ul&gt;
                        &lt;li&gt;&lt;strong&gt;공영주차장:&lt;/strong&gt; 매월 발매 공고를 미리 확인하고, 신청 시작과 동시에 빠르게 접속하여 선착순으로 신청&lt;/li&gt;
                        &lt;li&gt;&lt;strong&gt;민간주차장:&lt;/strong&gt; &lt;a href=&quot;https://www.moduparking.com/&quot; target=&quot;_blank&quot; style=&quot;color: #2d5016;&quot;&gt;모두의주차장&lt;/a&gt;, &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.skt.tmap.ku&quot; target=&quot;_blank&quot; style=&quot;color: #2d5016;&quot;&gt;TMAP&lt;/a&gt; 등의 앱을 활용하여 사전에 요금과 위치를 비교 검토&lt;/li&gt;
                        &lt;li&gt;&lt;strong&gt;가격 vs 편의성:&lt;/strong&gt; 공영주차장은 저렴하지만 경쟁이 치열하고, 민간주차장은 비싸지만 선택지가 많음&lt;/li&gt;
                        &lt;li&gt;&lt;strong&gt;할인 혜택:&lt;/strong&gt; 저공해차량, 장애인 등 해당 사항이 있다면 반드시 할인 혜택을 확인하고 신청&lt;/li&gt;
                    &lt;/ul&gt;
                &lt;/div&gt;

                &lt;div class=&quot;detail-cards&quot;&gt;
                    &lt;div class=&quot;detail-card&quot;&gt;
                        &lt;h3&gt; ️ 공영주차장 신청 전략&lt;/h3&gt;
                        &lt;p&gt;• 성동구 거주 기간이 길수록 유리&lt;/p&gt;
                        &lt;p&gt;• 매월 15일경 다음 달 신청 공고 확인&lt;/p&gt;
                        &lt;p&gt;• 신청 시간 정확히 맞춰서 접속&lt;/p&gt;
                        &lt;p&gt;• 여러 주차장에 동시 신청 가능한지 확인&lt;/p&gt;
                    &lt;/div&gt;
                    
                    &lt;div class=&quot;detail-card&quot;&gt;
                        &lt;h3&gt;  민간주차장 이용 전략&lt;/h3&gt;
                        &lt;p&gt;• 주차장 앱으로 사전 요금 비교&lt;/p&gt;
                        &lt;p&gt;• 월정기 할인 이벤트 시기 노려보기&lt;/p&gt;
                        &lt;p&gt;• 건물 관리사무소에 직접 문의&lt;/p&gt;
                        &lt;p&gt;• 계약 조건 및 환불 정책 확인&lt;/p&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;contact-section&quot;&gt;
                &lt;h3&gt;  문의 및 신청 연락처&lt;/h3&gt;
                &lt;div class=&quot;contact-grid&quot;&gt;
                    &lt;div class=&quot;contact-item&quot;&gt;
                        &lt;h4&gt; ️ 성동구 도시관리공단&lt;/h4&gt;
                        &lt;p&gt;&lt;strong&gt;홈페이지:&lt;/strong&gt; &lt;a href=&quot;https://parking.happysd.or.kr/&quot; target=&quot;_blank&quot; style=&quot;color: #74b9ff;&quot;&gt;parking.happysd.or.kr&lt;/a&gt;&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;전화번호:&lt;/strong&gt; 02-2202-5077&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;업무시간:&lt;/strong&gt; 평일 09:00~18:00&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;주차장 현황:&lt;/strong&gt; &lt;a href=&quot;https://parking.happysd.or.kr/Public/PresentTab2&quot; target=&quot;_blank&quot; style=&quot;color: #74b9ff;&quot;&gt;공영주차장 현황 보기&lt;/a&gt;&lt;/p&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;contact-item&quot;&gt;
                        &lt;h4&gt;  주차 앱 관련 연락처&lt;/h4&gt;
                        &lt;p&gt;&lt;strong&gt;모두의주차장:&lt;/strong&gt; 1899-8242&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;웹사이트:&lt;/strong&gt; &lt;a href=&quot;https://www.moduparking.com/&quot; target=&quot;_blank&quot; style=&quot;color: #74b9ff;&quot;&gt;moduparking.com&lt;/a&gt;&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;TMAP 주차:&lt;/strong&gt; 1544-7116&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;앱 다운로드:&lt;/strong&gt; &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.tmapparking.user&quot; target=&quot;_blank&quot; style=&quot;color: #74b9ff;&quot;&gt;TMAP 주차 앱&lt;/a&gt;&lt;/p&gt;
                        &lt;p&gt;&lt;strong&gt;특징:&lt;/strong&gt; 실시간 주차장 정보 및 할인 혜택 제공&lt;/p&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</description>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742129</guid>
      <comments>https://sojw.tistory.com/1169742129#entry1169742129comment</comments>
      <pubDate>Sun, 29 Jun 2025 02:17:55 +0900</pubDate>
    </item>
    <item>
      <title>국내 주요 증권사 앱(MTS) 비교 정리 (2025년 6월 기준)</title>
      <link>https://sojw.tistory.com/1169742128</link>
      <description>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;ko&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;증권사 MTS 간단 비교&lt;/title&gt;
    &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js&quot;&gt;&lt;/script&gt;
    &lt;style&gt;
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Malgun Gothic', -apple-system, BlinkMacSystemFont, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f8f9fa;
        }
        
        .container {
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
            background: white;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .header {
            text-align: center;
            padding: 30px 0;
            border-bottom: 2px solid #007bff;
            margin-bottom: 40px;
        }
        
        .header h1 {
            font-size: 2.2em;
            color: #2c3e50;
            margin-bottom: 10px;
        }
        
        .header .date {
            color: #6c757d;
            font-size: 1.1em;
        }
        
        .section {
            margin-bottom: 50px;
        }
        
        .section-title {
            font-size: 1.6em;
            color: #007bff;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 1px solid #dee2e6;
        }
        
        /* 테이블 스타일 */
        .comparison-table {
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
            background: white;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        
        .comparison-table th {
            background-color: #007bff;
            color: white;
            padding: 15px 10px;
            text-align: center;
            font-weight: 600;
        }
        
        .comparison-table td {
            padding: 12px 10px;
            text-align: center;
            border-bottom: 1px solid #dee2e6;
        }
        
        .comparison-table tr:nth-child(even) {
            background-color: #f8f9fa;
        }
        
        .comparison-table tr:hover {
            background-color: #e3f2fd;
        }
        
        .best-rate {
            background-color: #d4edda !important;
            font-weight: bold;
            color: #155724;
        }
        
        .event-rate {
            background-color: #fff3cd !important;
            font-weight: bold;
            color: #856404;
        }
        
        /* 홈페이지 링크 스타일 */
        .company-link {
            color: #007bff;
            text-decoration: none;
            font-weight: 600;
        }
        
        .company-link:hover {
            color: #0056b3;
            text-decoration: underline;
        }
        
        .link-icon {
            margin-left: 5px;
            font-size: 0.8em;
        }
        
        /* 차트 컨테이너 */
        .chart-container {
            position: relative;
            height: 350px;
            margin: 30px 0;
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        
        /* 특징 그리드 */
        .features-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            margin: 30px 0;
        }
        
        .feature-card {
            background: white;
            padding: 20px;
            border-left: 4px solid #007bff;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        
        .feature-card h4 {
            color: #007bff;
            margin-bottom: 10px;
            font-size: 1.2em;
        }
        
        .feature-card p {
            color: #6c757d;
            margin-bottom: 8px;
        }
        
        .feature-card .highlight {
            background-color: #007bff;
            color: white;
            padding: 2px 8px;
            border-radius: 12px;
            font-size: 0.85em;
            font-weight: 500;
        }
        
        /* 추천 섹션 */
        .recommendations {
            background-color: #f8f9fa;
            padding: 30px;
            border-radius: 8px;
            margin-top: 30px;
        }
        
        .recommendations h3 {
            color: #007bff;
            text-align: center;
            margin-bottom: 25px;
            font-size: 1.8em;
        }
        
        .recommendation-list {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 20px;
        }
        
        .recommendation-item {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        
        .recommendation-item h4 {
            color: #007bff;
            margin-bottom: 10px;
        }
        
        .recommendation-item .companies {
            font-weight: 600;
            color: #2c3e50;
            margin-bottom: 8px;
        }
        
        .recommendation-item .reason {
            color: #6c757d;
            font-size: 0.95em;
        }
        
        /* 요약 박스 */
        .summary-box {
            background: linear-gradient(135deg, #007bff, #0056b3);
            color: white;
            padding: 25px;
            border-radius: 8px;
            margin: 30px 0;
        }
        
        .summary-box h4 {
            margin-bottom: 15px;
            font-size: 1.3em;
        }
        
        .summary-box ul {
            list-style: none;
        }
        
        .summary-box li {
            margin-bottom: 8px;
            padding-left: 20px;
            position: relative;
        }
        
        .summary-box li:before {
            content: &quot;✓&quot;;
            position: absolute;
            left: 0;
            color: #28a745;
            font-weight: bold;
        }
        
        /* 홈페이지 링크 섹션 */
        .links-section {
            background-color: #f8f9fa;
            padding: 30px;
            border-radius: 8px;
            margin-top: 30px;
        }
        
        .links-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 15px;
            margin-top: 20px;
        }
        
        .link-item {
            background: white;
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            text-align: center;
        }
        
        .link-item a {
            color: #007bff;
            text-decoration: none;
            font-weight: 600;
            display: block;
            padding: 10px;
            border-radius: 5px;
            transition: all 0.3s ease;
        }
        
        .link-item a:hover {
            background-color: #007bff;
            color: white;
            text-decoration: none;
        }
        
        @media (max-width: 768px) {
            .container {
                padding: 15px;
            }
            
            .header h1 {
                font-size: 1.8em;
            }
            
            .comparison-table {
                font-size: 0.9em;
            }
            
            .comparison-table th,
            .comparison-table td {
                padding: 8px 5px;
            }
            
            .chart-container {
                height: 300px;
                padding: 15px;
            }
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;container&quot;&gt;
        &lt;!-- 헤더 --&gt;
        &lt;div class=&quot;header&quot;&gt;
            &lt;h1&gt;국내 주요 증권사 MTS 비교&lt;/h1&gt;
            &lt;div class=&quot;date&quot;&gt;2025년 기준&lt;/div&gt;
        &lt;/div&gt;
        
        &lt;!-- 1. 수수료 비교 --&gt;
        &lt;div class=&quot;section&quot;&gt;
            &lt;div class=&quot;section-title&quot;&gt;1. 수수료 비교&lt;/div&gt;
            
            &lt;table class=&quot;comparison-table&quot;&gt;
                &lt;thead&gt;
                    &lt;tr&gt;
                        &lt;th&gt;증권사&lt;/th&gt;
                        &lt;th&gt;앱명&lt;/th&gt;
                        &lt;th&gt;수수료율&lt;/th&gt;
                        &lt;th&gt;1천만원 거래시&lt;/th&gt;
                        &lt;th&gt;비고&lt;/th&gt;
                    &lt;/tr&gt;
                &lt;/thead&gt;
                &lt;tbody&gt;
                    &lt;tr class=&quot;best-rate&quot;&gt;
                        &lt;td&gt;&lt;a href=&quot;https://www.samsungpop.com&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;삼성증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;mPOP&lt;/td&gt;
                        &lt;td&gt;0.0036%&lt;/td&gt;
                        &lt;td&gt;364원&lt;/td&gt;
                        &lt;td&gt;최저 수준&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr class=&quot;best-rate&quot;&gt;
                        &lt;td&gt;&lt;a href=&quot;https://www.miraeasset.com&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;미래에셋증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;m.Stock&lt;/td&gt;
                        &lt;td&gt;0.0036%&lt;/td&gt;
                        &lt;td&gt;364원&lt;/td&gt;
                        &lt;td&gt;최저 수준&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr class=&quot;best-rate&quot;&gt;
                        &lt;td&gt;&lt;a href=&quot;https://www.truefriend.com&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;한국투자증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;eFriend Smart&lt;/td&gt;
                        &lt;td&gt;0.0036%&lt;/td&gt;
                        &lt;td&gt;364원&lt;/td&gt;
                        &lt;td&gt;최저 수준&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr class=&quot;event-rate&quot;&gt;
                        &lt;td&gt;&lt;a href=&quot;https://www.nhqv.com&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;NH투자증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;나무&lt;/td&gt;
                        &lt;td&gt;0.0043% → 0.01%&lt;/td&gt;
                        &lt;td&gt;433원 → 1,000원&lt;/td&gt;
                        &lt;td&gt;이벤트 기간 후 인상&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;&lt;a href=&quot;https://www.kiwoom.com&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;키움증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;영웅문S#&lt;/td&gt;
                        &lt;td&gt;0.015%&lt;/td&gt;
                        &lt;td&gt;1,500원&lt;/td&gt;
                        &lt;td&gt;전문가 기능 특화&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;&lt;a href=&quot;https://www.kbsec.com&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;KB증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;M-able&lt;/td&gt;
                        &lt;td&gt;0.015%&lt;/td&gt;
                        &lt;td&gt;1,500원&lt;/td&gt;
                        &lt;td&gt;초보자 친화적&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;&lt;a href=&quot;https://www.meritz.co.kr&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;메리츠증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;mCLASS&lt;/td&gt;
                        &lt;td&gt;0.015%&lt;/td&gt;
                        &lt;td&gt;1,500원&lt;/td&gt;
                        &lt;td&gt;미국주식 무료&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;&lt;a href=&quot;https://www.hanaw.com&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;한화투자증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;통합 MTS&lt;/td&gt;
                        &lt;td&gt;0.015%&lt;/td&gt;
                        &lt;td&gt;1,500원&lt;/td&gt;
                        &lt;td&gt;AI 기능 강화&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;&lt;a href=&quot;https://securities.toss.im&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;토스증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;토스증권&lt;/td&gt;
                        &lt;td&gt;0.015%&lt;/td&gt;
                        &lt;td&gt;1,500원&lt;/td&gt;
                        &lt;td&gt;최고 UX 평가&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;&lt;a href=&quot;https://securities.kakaopay.com&quot; target=&quot;_blank&quot; class=&quot;company-link&quot;&gt;카카오페이증권&lt;span class=&quot;link-icon&quot;&gt; &lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
                        &lt;td&gt;카카오페이증권&lt;/td&gt;
                        &lt;td&gt;0.015%&lt;/td&gt;
                        &lt;td&gt;1,500원&lt;/td&gt;
                        &lt;td&gt;간편 송금 연계&lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/tbody&gt;
            &lt;/table&gt;
            
            &lt;div class=&quot;summary-box&quot;&gt;
                &lt;h4&gt;  수수료 핵심 정리&lt;/h4&gt;
                &lt;ul&gt;
                    &lt;li&gt;최저 수수료: 삼성, 미래에셋, 한국투자증권 (0.0036%)&lt;/li&gt;
                    &lt;li&gt;NH투자증권은 이벤트 기간 후 수수료 인상 예정&lt;/li&gt;
                    &lt;li&gt;1천만원 거래 기준 최대 4배 차이 (364원 vs 1,500원)&lt;/li&gt;
                    &lt;li&gt;빈번한 거래자는 수수료 차이가 크게 영향&lt;/li&gt;
                &lt;/ul&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        
        &lt;!-- 2. 사용자 수 현황 --&gt;
        &lt;div class=&quot;section&quot;&gt;
            &lt;div class=&quot;section-title&quot;&gt;2. 월간 활성 사용자 수 (MAU)&lt;/div&gt;
            
            &lt;div class=&quot;chart-container&quot;&gt;
                &lt;canvas id=&quot;mauChart&quot;&gt;&lt;/canvas&gt;
            &lt;/div&gt;
            
            &lt;table class=&quot;comparison-table&quot;&gt;
                &lt;thead&gt;
                    &lt;tr&gt;
                        &lt;th&gt;순위&lt;/th&gt;
                        &lt;th&gt;증권사&lt;/th&gt;
                        &lt;th&gt;MAU&lt;/th&gt;
                        &lt;th&gt;특징&lt;/th&gt;
                    &lt;/tr&gt;
                &lt;/thead&gt;
                &lt;tbody&gt;
                    &lt;tr&gt;
                        &lt;td&gt;1위&lt;/td&gt;
                        &lt;td&gt;NH투자증권 나무&lt;/td&gt;
                        &lt;td&gt;418만명&lt;/td&gt;
                        &lt;td&gt;압도적 1위, 꾸준한 상승&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;2위&lt;/td&gt;
                        &lt;td&gt;키움증권 영웅문S#&lt;/td&gt;
                        &lt;td&gt;260만명&lt;/td&gt;
                        &lt;td&gt;전문가층 중심 안정적 유지&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;3위&lt;/td&gt;
                        &lt;td&gt;삼성증권 mPOP&lt;/td&gt;
                        &lt;td&gt;228만명&lt;/td&gt;
                        &lt;td&gt;AI 기능으로 사용자 증가&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;4위&lt;/td&gt;
                        &lt;td&gt;미래에셋증권 m.Stock&lt;/td&gt;
                        &lt;td&gt;225만명&lt;/td&gt;
                        &lt;td&gt;해외주식 기능 개선으로 상승&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;5위&lt;/td&gt;
                        &lt;td&gt;KB증권 M-able&lt;/td&gt;
                        &lt;td&gt;194만명&lt;/td&gt;
                        &lt;td&gt;편의성으로 꾸준한 증가&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;6위&lt;/td&gt;
                        &lt;td&gt;한국투자증권 eFriend&lt;/td&gt;
                        &lt;td&gt;80만명&lt;/td&gt;
                        &lt;td&gt;안정적 유지&lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/tbody&gt;
            &lt;/table&gt;
        &lt;/div&gt;
        
        &lt;!-- 3. 앱 기능 특징 --&gt;
        &lt;div class=&quot;section&quot;&gt;
            &lt;div class=&quot;section-title&quot;&gt;3. 앱 활용성 및 주요 기능&lt;/div&gt;
            
            &lt;div class=&quot;features-grid&quot;&gt;
                &lt;div class=&quot;feature-card&quot;&gt;
                    &lt;h4&gt;키움증권 영웅문S#&lt;/h4&gt;
                    &lt;p&gt;&lt;span class=&quot;highlight&quot;&gt;전문가 선호&lt;/span&gt;&lt;/p&gt;
                    &lt;p&gt;• HTS급 기능 제공&lt;/p&gt;
                    &lt;p&gt;• 고급 차트 분석&lt;/p&gt;
                    &lt;p&gt;• 자동매매 시스템&lt;/p&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;feature-card&quot;&gt;
                    &lt;h4&gt;삼성증권 mPOP&lt;/h4&gt;
                    &lt;p&gt;&lt;span class=&quot;highlight&quot;&gt;AI 특화&lt;/span&gt;&lt;/p&gt;
                    &lt;p&gt;• 리서치 기능 우수&lt;/p&gt;
                    &lt;p&gt;• AI 포트폴리오 제공&lt;/p&gt;
                    &lt;p&gt;• 인공지능 투자 도구&lt;/p&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;feature-card&quot;&gt;
                    &lt;h4&gt;미래에셋증권 m.Stock&lt;/h4&gt;
                    &lt;p&gt;&lt;span class=&quot;highlight&quot;&gt;해외투자&lt;/span&gt;&lt;/p&gt;
                    &lt;p&gt;• 해외주식 원스톱 기능&lt;/p&gt;
                    &lt;p&gt;• 직관적 UI&lt;/p&gt;
                    &lt;p&gt;• 글로벌 투자 특화&lt;/p&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;feature-card&quot;&gt;
                    &lt;h4&gt;NH투자증권 나무&lt;/h4&gt;
                    &lt;p&gt;&lt;span class=&quot;highlight&quot;&gt;사용자 1위&lt;/span&gt;&lt;/p&gt;
                    &lt;p&gt;• 빠른 속도&lt;/p&gt;
                    &lt;p&gt;• 초보자 친화적 인터페이스&lt;/p&gt;
                    &lt;p&gt;• 편리한 기능 제공&lt;/p&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;feature-card&quot;&gt;
                    &lt;h4&gt;토스증권&lt;/h4&gt;
                    &lt;p&gt;&lt;span class=&quot;highlight&quot;&gt;최고 UX&lt;/span&gt;&lt;/p&gt;
                    &lt;p&gt;• 직관적이고 깔끔한 디자인&lt;/p&gt;
                    &lt;p&gt;• 핀테크 기반 혁신&lt;/p&gt;
                    &lt;p&gt;• 간편한 사용성&lt;/p&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;feature-card&quot;&gt;
                    &lt;h4&gt;메리츠증권 mCLASS&lt;/h4&gt;
                    &lt;p&gt;&lt;span class=&quot;highlight&quot;&gt;미국주식 무료&lt;/span&gt;&lt;/p&gt;
                    &lt;p&gt;• 미국주식 거래 특화&lt;/p&gt;
                    &lt;p&gt;• 해외투자 혜택 중심&lt;/p&gt;
                    &lt;p&gt;• 급성장 중&lt;/p&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        
        &lt;!-- 4. 투자 스타일별 추천 --&gt;
        &lt;div class=&quot;recommendations&quot;&gt;
            &lt;h3&gt;투자 스타일별 맞춤 추천&lt;/h3&gt;
            
            &lt;div class=&quot;recommendation-list&quot;&gt;
                &lt;div class=&quot;recommendation-item&quot;&gt;
                    &lt;h4&gt;  최저 수수료 중심&lt;/h4&gt;
                    &lt;div class=&quot;companies&quot;&gt;삼성증권, 미래에셋증권, 한국투자증권&lt;/div&gt;
                    &lt;div class=&quot;reason&quot;&gt;동일한 최저 수수료 0.0036%, 빈번한 거래자에게 유리&lt;/div&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;recommendation-item&quot;&gt;
                    &lt;h4&gt;  전문가급 기능&lt;/h4&gt;
                    &lt;div class=&quot;companies&quot;&gt;키움증권 영웅문S#&lt;/div&gt;
                    &lt;div class=&quot;reason&quot;&gt;HTS급 차트, 자동매매, 고급 분석 도구 제공&lt;/div&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;recommendation-item&quot;&gt;
                    &lt;h4&gt;  초보자 &amp; UX 우선&lt;/h4&gt;
                    &lt;div class=&quot;companies&quot;&gt;NH 나무, KB M-able, 토스증권&lt;/div&gt;
                    &lt;div class=&quot;reason&quot;&gt;직관적 인터페이스, 편리한 기능, 높은 사용자 만족도&lt;/div&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;recommendation-item&quot;&gt;
                    &lt;h4&gt;  해외투자 &amp; AI&lt;/h4&gt;
                    &lt;div class=&quot;companies&quot;&gt;한화투자증권, 미래에셋증권&lt;/div&gt;
                    &lt;div class=&quot;reason&quot;&gt;AI 기능, 해외주식 특화, 글로벌 투자 도구&lt;/div&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;recommendation-item&quot;&gt;
                    &lt;h4&gt;  미국주식 중심&lt;/h4&gt;
                    &lt;div class=&quot;companies&quot;&gt;메리츠증권 mCLASS&lt;/div&gt;
                    &lt;div class=&quot;reason&quot;&gt;미국주식 거래 수수료 무료, 해외투자 혜택&lt;/div&gt;
                &lt;/div&gt;
                
                &lt;div class=&quot;recommendation-item&quot;&gt;
                    &lt;h4&gt;  간편투자&lt;/h4&gt;
                    &lt;div class=&quot;companies&quot;&gt;토스증권, 카카오페이증권&lt;/div&gt;
                    &lt;div class=&quot;reason&quot;&gt;핀테크 기반, 간편 송금 연계, 혁신적 UX&lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        
        &lt;!-- 5. 증권사 홈페이지 링크 --&gt;
        &lt;div class=&quot;links-section&quot;&gt;
            &lt;h3 style=&quot;color: #007bff; text-align: center; margin-bottom: 20px;&quot;&gt;증권사 홈페이지 바로가기&lt;/h3&gt;
            &lt;div class=&quot;links-grid&quot;&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://www.samsungpop.com&quot; target=&quot;_blank&quot;&gt;삼성증권&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://www.miraeasset.com&quot; target=&quot;_blank&quot;&gt;미래에셋증권&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://www.truefriend.com&quot; target=&quot;_blank&quot;&gt;한국투자증권&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://www.nhqv.com&quot; target=&quot;_blank&quot;&gt;NH투자증권&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://www.kiwoom.com&quot; target=&quot;_blank&quot;&gt;키움증권&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://www.kbsec.com&quot; target=&quot;_blank&quot;&gt;KB증권&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://www.meritz.co.kr&quot; target=&quot;_blank&quot;&gt;메리츠증권&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://www.hanaw.com&quot; target=&quot;_blank&quot;&gt;한화투자증권&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://securities.toss.im&quot; target=&quot;_blank&quot;&gt;토스증권&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class=&quot;link-item&quot;&gt;
                    &lt;a href=&quot;https://securities.kakaopay.com&quot; target=&quot;_blank&quot;&gt;카카오페이증권&lt;/a&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;script&gt;
        // MAU 차트 (막대 차트로 단순화)
        const mauCtx = document.getElementById('mauChart').getContext('2d');
        new Chart(mauCtx, {
            type: 'bar',
            data: {
                labels: ['NH투자\n나무', '키움\n영웅문S#', '삼성\nmPOP', '미래에셋\nm.Stock', 'KB\nM-able', '한국투자\neFriend'],
                datasets: [{
                    label: 'MAU (만명)',
                    data: [418, 260, 228, 225, 194, 80],
                    backgroundColor: [
                        '#007bff', '#0056b3', '#17a2b8', '#28a745', '#ffc107', '#6c757d'
                    ],
                    borderColor: [
                        '#0056b3', '#004085', '#138496', '#1e7e34', '#e0a800', '#545b62'
                    ],
                    borderWidth: 1
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        display: false
                    },
                    tooltip: {
                        callbacks: {
                            label: function(context) {
                                return context.parsed.y.toLocaleString() + '만명';
                            }
                        }
                    }
                },
                scales: {
                    y: {
                        beginAtZero: true,
                        ticks: {
                            callback: function(value) {
                                return value + '만';
                            }
                        },
                        grid: {
                            color: 'rgba(0,0,0,0.1)'
                        }
                    },
                    x: {
                        ticks: {
                            maxRotation: 0,
                            font: {
                                size: 11
                            }
                        },
                        grid: {
                            display: false
                        }
                    }
                }
            }
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</description>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742128</guid>
      <comments>https://sojw.tistory.com/1169742128#entry1169742128comment</comments>
      <pubDate>Sun, 29 Jun 2025 01:52:07 +0900</pubDate>
    </item>
    <item>
      <title>Software Algorithm 10</title>
      <link>https://sojw.tistory.com/1169742127</link>
      <description>&lt;h3 id=&quot;1-dfs-깊이-우선-탐색-depth-first-search&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DFS (깊이 우선 탐색, Depth-First Search)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;6&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 그래프 탐색, 백트래킹, 경로 찾기&lt;/li&gt;
&lt;li data-source-line=&quot;7&quot;&gt;&lt;b&gt;특징&lt;/b&gt;: 한 경로를 끝까지 탐색한 후 다른 경로로 넘어가는 방식&lt;/li&gt;
&lt;li data-source-line=&quot;8&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: 미로 찾기, 섬의 개수 세기, 그래프에서의 경로 탐색&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;10&quot; data-info=&quot;python {data-source-line=&amp;quot;10&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;def dfs(graph, v, visited):
    visited[v] = True
    print(v, end=' ')
    for i in graph[v]:
        if not visited[i]:
            dfs(graph, i, visited)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-bfs-너비-우선-탐색-breadth-first-search&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;BFS (너비 우선 탐색, Breadth-First Search)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;20&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 그래프 탐색, 최단 경로 탐색&lt;/li&gt;
&lt;li data-source-line=&quot;21&quot;&gt;&lt;b&gt;특징&lt;/b&gt;: 가까운 노드부터 탐색하는 방식 (큐를 사용)&lt;/li&gt;
&lt;li data-source-line=&quot;22&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: 최단 경로 문제, 미로 찾기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;24&quot; data-info=&quot;python {data-source-line=&amp;quot;24&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;from collections import deque

def bfs(graph, start, visited):
    queue = deque([start])
    visited[start] = True
    while queue:
        v = queue.popleft()
        print(v, end=' ')
        for i in graph[v]:
            if not visited[i]:
                queue.append(i)
                visited[i] = True
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-이진-탐색-binary-search&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;39&quot; data-ke-size=&quot;size23&quot;&gt;3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이진 탐색 (Binary Search)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;40&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;40&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 정렬된 배열에서의 탐색&lt;/li&gt;
&lt;li data-source-line=&quot;41&quot;&gt;&lt;b&gt;특징&lt;/b&gt;: 중간값과 비교해 탐색 범위를 절반씩 줄여나가는 방식&lt;/li&gt;
&lt;li data-source-line=&quot;42&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: 특정 값 찾기, 범위를 빠르게 좁히는 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;livecodeserver&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;44&quot; data-info=&quot;python {data-source-line=&amp;quot;44&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    while left &amp;lt;= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] &amp;lt; target:
            left = mid + 1
        else:
            right = mid - 1
    return -1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;4-다익스트라-알고리즘-dijkstras-algorithm&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;58&quot; data-ke-size=&quot;size23&quot;&gt;4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다익스트라 알고리즘 (Dijkstra's Algorithm)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;59&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;59&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 가중치가 있는 그래프에서의 최단 경로 탐색&lt;/li&gt;
&lt;li data-source-line=&quot;60&quot;&gt;&lt;b&gt;특징&lt;/b&gt;: 우선순위 큐(최소 힙)를 사용해 현재까지의 최단 경로를 계속 갱신하는 방식&lt;/li&gt;
&lt;li data-source-line=&quot;61&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: 특정 노드에서 다른 노드까지의 최단 경로&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;63&quot; data-info=&quot;python {data-source-line=&amp;quot;63&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;import heapq

def dijkstra(graph, start):
    distances = {node: float('inf') for node in graph}
    distances[start] = 0
    queue = [(0, start)]
    
    while queue:
        current_distance, current_node = heapq.heappop(queue)
        
        if current_distance &amp;gt; distances[current_node]:
            continue
        
        for adjacent, weight in graph[current_node].items():
            distance = current_distance + weight
            if distance &amp;lt; distances[adjacent]:
                distances[adjacent] = distance
                heapq.heappush(queue, (distance, adjacent))
    
    return distances
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;5-동적-계획법-dynamic-programming-dp&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;86&quot; data-ke-size=&quot;size23&quot;&gt;5.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;동적 계획법 (Dynamic Programming, DP)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;87&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;87&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 작은 문제를 풀고, 그 결과를 저장해서 큰 문제를 푸는 방식&lt;/li&gt;
&lt;li data-source-line=&quot;88&quot;&gt;&lt;b&gt;특징&lt;/b&gt;: 재귀적 접근과 메모이제이션을 사용해 중복 계산을 피함&lt;/li&gt;
&lt;li data-source-line=&quot;89&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: 피보나치 수열, 배낭 문제, 최소 비용 경로&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;excel&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;91&quot; data-info=&quot;python {data-source-line=&amp;quot;91&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;def fib(n, memo={}):
    if n in memo:
        return memo[n]
    if n &amp;lt;= 1:
        return n
    memo[n] = fib(n-1, memo) + fib(n-2, memo)
    return memo[n]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;6-최소-신장-트리-minimum-spanning-tree-mst&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;101&quot; data-ke-size=&quot;size23&quot;&gt;6.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;최소 신장 트리 (Minimum Spanning Tree, MST)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;102&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;102&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 그래프에서 모든 정점을 연결하는 최소 비용의 트리 구하기&lt;/li&gt;
&lt;li data-source-line=&quot;103&quot;&gt;&lt;b&gt;주요 알고리즘&lt;/b&gt;: Kruskal's Algorithm, Prim's Algorithm&lt;/li&gt;
&lt;li data-source-line=&quot;104&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: 네트워크 연결, 도로 건설&lt;/li&gt;
&lt;li data-source-line=&quot;106&quot;&gt;&lt;b&gt;크루스칼 알고리즘&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Kruskal's Algorithm):
&lt;ul style=&quot;list-style-type: circle;&quot; data-source-line=&quot;107&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li data-source-line=&quot;107&quot;&gt;간선을 정렬한 후 최소 비용으로 연결하는 방식 (Union-Find 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;mel&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;109&quot; data-info=&quot;python {data-source-line=&amp;quot;109&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;def find(parent, x):
    if parent[x] != x:
        parent[x] = find(parent, parent[x])
    return parent[x]

def union(parent, a, b):
    rootA = find(parent, a)
    rootB = find(parent, b)
    if rootA &amp;lt; rootB:
        parent[rootB] = rootA
    else:
        parent[rootA] = rootB
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;7-투-포인터-two-pointer&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;124&quot; data-ke-size=&quot;size23&quot;&gt;7.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;투 포인터 (Two Pointer)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;125&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;125&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 배열에서 두 개의 포인터를 사용해 특정 조건을 만족하는 구간 찾기&lt;/li&gt;
&lt;li data-source-line=&quot;126&quot;&gt;&lt;b&gt;특징&lt;/b&gt;: 양 끝에서 포인터를 이동시켜가며 문제 해결&lt;/li&gt;
&lt;li data-source-line=&quot;127&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: 부분합 구하기, 특정 구간 찾기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;vim&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;129&quot; data-info=&quot;python {data-source-line=&amp;quot;129&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;def two_pointer(arr, target):
    left, right = 0, len(arr) - 1
    while left &amp;lt; right:
        current_sum = arr[left] + arr[right]
        if current_sum == target:
            return (left, right)
        elif current_sum &amp;lt; target:
            left += 1
        else:
            right -= 1
    return None
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;8-슬라이딩-윈도우-sliding-window&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;143&quot; data-ke-size=&quot;size23&quot;&gt;8.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;슬라이딩 윈도우 (Sliding Window)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;144&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;144&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 고정된 크기 또는 가변적인 크기의 구간을 이동하면서 문제 해결&lt;/li&gt;
&lt;li data-source-line=&quot;145&quot;&gt;&lt;b&gt;특징&lt;/b&gt;: 부분 합, 최대값/최소값을 구하는 문제에 적합&lt;/li&gt;
&lt;li data-source-line=&quot;146&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: 최대 부분합 구하기, 문자열에서 특정 패턴 찾기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;properties&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;148&quot; data-info=&quot;python {data-source-line=&amp;quot;148&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;def sliding_window(arr, k):
    current_sum = sum(arr[:k])
    max_sum = current_sum
    
    for i in range(k, len(arr)):
        current_sum += arr[i] - arr[i - k]
        max_sum = max(max_sum, current_sum)
    
    return max_sum
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;9-유니온-파인드-union-find&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;160&quot; data-ke-size=&quot;size23&quot;&gt;9.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;유니온 파인드 (Union-Find)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;161&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;161&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 그래프에서 연결된 컴포넌트를 찾는 알고리즘
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-source-line=&quot;162&quot;&gt;&lt;b&gt;특징&lt;/b&gt;: 집합을 합치고 연결 여부를 판단할 때 사용 (서로소 집합)&lt;/li&gt;
&lt;li data-source-line=&quot;163&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: 사이클 판별, 네트워크 연결 여부 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;mel&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;165&quot; data-info=&quot;python {data-source-line=&amp;quot;165&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;def find(parent, x):
    if parent[x] != x:
        parent[x] = find(parent, parent[x])
    return parent[x]

def union(parent, a, b):
    rootA = find(parent, a)
    rootB = find(parent, b)
    if rootA != rootB:
        parent[rootB] = rootA
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;10-백트래킹-backtracking&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-source-line=&quot;178&quot; data-ke-size=&quot;size23&quot;&gt;10.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;백트래킹 (Backtracking)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;179&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;179&quot;&gt;&lt;b&gt;사용&lt;/b&gt;: 가능한 모든 경우를 탐색하면서 조건을 만족하는 해를 찾는 방식&lt;/li&gt;
&lt;li data-source-line=&quot;180&quot;&gt;&lt;b&gt;특징&lt;/b&gt;: 해를 찾다가 조건에 맞지 않으면 이전 단계로 돌아가는 방식&lt;/li&gt;
&lt;li data-source-line=&quot;181&quot;&gt;&lt;b&gt;응용 문제&lt;/b&gt;: N-Queen 문제, 부분 집합 구하기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ruby&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: left;&quot; data-source-line=&quot;183&quot; data-info=&quot;python {data-source-line=&amp;quot;183&amp;quot;}&quot; data-role=&quot;codeBlock&quot;&gt;&lt;code&gt;def backtracking(path, choices):
    if 조건에 만족:
        결과 저장
        return
    for choice in choices:
        if 조건에 맞는 choice:
            backtracking(path + [choice], choices)
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;193&quot; data-ke-size=&quot;size16&quot;&gt;이 외에도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정렬 알고리즘&lt;/b&gt;(퀵 정렬, 병합 정렬),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;그리디 알고리즘&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문자열 처리 알고리즘&lt;/b&gt;(KMP, 라빈-카프 알고리즘) 등이 코딩 테스트에서 자주 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742127</guid>
      <comments>https://sojw.tistory.com/1169742127#entry1169742127comment</comments>
      <pubDate>Fri, 25 Oct 2024 23:13:39 +0900</pubDate>
    </item>
    <item>
      <title>Why you should never default to Microservices</title>
      <link>https://sojw.tistory.com/1169742126</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://levelup.gitconnected.com/why-you-should-never-default-to-microservices-c952903fbcb6&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://levelup.gitconnected.com/why-you-should-never-default-to-microservices-c952903fbcb6&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729681323132&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;Why you should never default to Microservices&quot; data-og-description=&quot;Disclaimer: Grumpy Goose Warning&quot; data-og-host=&quot;levelup.gitconnected.com&quot; data-og-source-url=&quot;https://levelup.gitconnected.com/why-you-should-never-default-to-microservices-c952903fbcb6&quot; data-og-url=&quot;https://levelup.gitconnected.com/why-you-should-never-default-to-microservices-c952903fbcb6&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bTQcqy/hyXlJtagfD/19qnuCqYs9csOpPTmXcPFk/img.png?width=463&amp;amp;height=410&amp;amp;face=0_0_463_410&quot;&gt;&lt;a href=&quot;https://levelup.gitconnected.com/why-you-should-never-default-to-microservices-c952903fbcb6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://levelup.gitconnected.com/why-you-should-never-default-to-microservices-c952903fbcb6&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bTQcqy/hyXlJtagfD/19qnuCqYs9csOpPTmXcPFk/img.png?width=463&amp;amp;height=410&amp;amp;face=0_0_463_410');&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;Why you should never default to Microservices&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Disclaimer: Grumpy Goose Warning&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;levelup.gitconnected.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;h1 id=&quot;a923&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;Complexity in Testing&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어는 99개의 기능이 올바르게 동작하고 1개의 기능이 실패했을 때, 그 99개의 성공에 대해 점수를 얻지 못하기 때문에 어렵습니다. 모든 것이 제대로 작동해야 합니다. 따라서 모든 것을 함께 테스트하거나, 테스트 범위가 넓어져야 합니다.&lt;br /&gt;테스트 범위는 단일 테스트 내에서 얼마나 많은 것을 테스트할 수 있는지를 측정하는 척도입니다.&lt;br /&gt;범위가 작을수록 실제 사용자 경험에서 멀어지게 됩니다. 즉, 테스트가 통과하더라도 기능이 제대로 동작한다는 의미는 덜하고, 테스트가 실패하더라도 기능이 제대로 작동하지 않는다는 의미는 덜하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모놀리식 구조에서는 큰 범위를 테스트하는 것이 쉽습니다.&lt;/b&gt;&lt;br /&gt;왜냐하면 모놀리식 구조는 모든 것을 다루기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 마이크로서비스에서는 같은 과정이 더 복잡해집니다.&lt;br /&gt;마이크로서비스에서는 테스트 범위가 마이크로서비스의 자연적인 경계에 의해 제한됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일반적인 마이크로서비스 테스트 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 우리는 동작을 모의(Mock)하거나 스텁(Stub)해야만 합니다.&lt;br /&gt;이는 주문 서비스나 이행 서비스에서 변경되거나 추가된 동작이 무시된다는 의미입니다.&lt;br /&gt;따라서, 테스트가 통과한다고 해서 기능이 제대로 작동할 가능성은 더 적어지고, 테스트가 실패한다고 해서 기능이 제대로 작동하지 않는다는 의미는 덜하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 수준에서 10,000개의 테스트가 통과하더라도, 여전히 아래와 같은 버그들이 발생할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비즈니스 로직의 변화로 인해 발생하는 다양한 오류&lt;/li&gt;
&lt;li&gt;주문 서비스나 상품 서비스의 데이터나 계약에서 발생하는 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 상호작용을 실제로 테스트하지 않고, 대신 이를 모의하고 있기 때문입니다.&lt;br /&gt;처음에는 문제가 되지 않더라도, 프로세스가 복잡해지고 변화함에 따라 문제가 될 것입니다.&lt;br /&gt;그 결과 UAT(사용자 수용 테스트)에서 더 많은 버그를 발견하게 되거나, 모의 객체들을 더 지능적으로 만들어야 할 것입니다. 이는 시간을 낭비하는 좋은 방법이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식은 각 개발자가 코드를 병합하기 전에 수동으로 두 가지를 함께 테스트해야 한다는 지식과 주의에 의존합니다. 제 경험상, 이것은 일관성이 없습니다.&lt;br /&gt;결국, 버그는 자동화된 테스트보다는 수동 테스트를 통해 UAT에서 발견됩니다. 이는 마치 10파운드짜리 버거를 100파운드에 사는 것과 같습니다.&lt;br /&gt;이러한 문제들이 놓쳐서 실제 프로덕션에 배포된다면, 이는 1000파운드를 쓰는 것과 마찬가지입니다.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모놀리식 구조에서는 이와 같은 테스트 스위트를 쉽게 가질 수 있습니다.&lt;/b&gt;&lt;br /&gt;모의 객체(Mock), 스텁(Stub), 가짜 데이터(fake), 속임수 없이 모든 것을 테스트할 수 있는 범위를 제공하므로, 테스트가 통과하면 기능이 실제로 작동할 가능성이 더 높아지고, 테스트가 실패하면 기능이 작동하지 않는다는 의미가 더 명확해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식은 훨씬 간단한 테스트 방법입니다.&lt;br /&gt;이는 그날의 경험, 지식, 완벽함, 혹은 충분한 카페인이 없어도 작동합니다.&lt;br /&gt;모의 객체(Mock)를 최신 상태로 유지하거나 지능적으로 만들 필요도 없습니다.&lt;br /&gt;그리고 정말로 하나의 서비스를 모의하고 싶다면, 매우 간단하게 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;2c0f&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;Complicating your infrastructure&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 웹 시스템 안에서 서로 통신해야 하는 작업에 갇히면, 상황이 매우 빠르게 복잡해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단계 추가하기&lt;/b&gt;&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;b&gt;모놀리식 구조&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;엔드포인트 생성&lt;/li&gt;
&lt;li&gt;엔드포인트에 대한 권한 생성&lt;/li&gt;
&lt;li&gt;프론트엔드에 엔드포인트 연결&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마이크로서비스 구조&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;엔드포인트 생성&lt;/li&gt;
&lt;li&gt;엔드포인트에 대한 사용자 권한 생성&lt;/li&gt;
&lt;li&gt;엔드포인트 인프라 생성&lt;/li&gt;
&lt;li&gt;새로운 마이크로서비스를 위한 파이프라인 생성&lt;/li&gt;
&lt;li&gt;n &amp;mdash; 모든 마이크로서비스가 이 엔드포인트와 통신할 수 있도록 권한 생성&lt;/li&gt;
&lt;li&gt;n &amp;mdash; 모든 인프라 코드를 올바르게 업데이트하고, 직접 수정된 것이 없는지 확인&lt;/li&gt;
&lt;li&gt;n &amp;mdash; 엔드포인트를 연결&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 3단계에서 4 + (3 * n)단계로 바뀌었습니다.&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;h1 id=&quot;8bf1&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;Managing split timelines&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 인프라가 완전히 별도의 인프라 팀에 의해 관리된다면(제가 절대 추천하지 않는 방식), 인도(배포)는 거의 확실하게 어려울 것입니다. 그들이 아무리 잘하더라도 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당신이 답해야 하는 질문은 &quot;다음 스프린트 내에 이 작업을 완료할 수 있을까요?&quot;가 아닙니다.&lt;br /&gt;대신에 다음과 같은 질문들을 답해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;다음 스프린트 내에 이 작업을 완료할 수 있을까요?&quot;&lt;/li&gt;
&lt;li&gt;&quot;인프라 팀이 다음 스프린트 내에 이 작업을 끝낼 수 있을까요? 그리고 그들이 우리를 차단하지 않도록 제시간에 준비할 수 있을까요?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역사적으로 볼 때, 첫 번째 질문에 대한 답은 &quot;네&quot;일지 몰라도, 두 번째 질문에 대한 답은 &quot;아니요&quot;일 가능성이 큽니다.&lt;br /&gt;이는 인프라 팀의 잘못이 아니며, 그냥 현실입니다. 이 상황에서 그 팀을 비즈니스 팀, QA 팀, 배포 팀, 또는 다른 어떤 팀으로 대체해도 마찬가지입니다.&lt;br /&gt;한 개의 타임라인이 아니라 여러 개의 타임라인을 관리하게 되면, 우선순위와 일정이 충돌하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 프로젝트 매니저가 &quot;이 기간 내에 이 작업을 완료할 수 있나요?&quot;라고 물으면, 대답이 &quot;네/아니요&quot;에서 &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;타임라인을 분리하면 한 팀에서 할 수 있는 것에 따라 단축이나 타협을 유도할 수 있습니다. 이것은 더 나쁜 설계로 이어질 수 있으며, 이는 프로젝트에서 할 수 있는 두 번째로 비용이 많이 드는 일일 수 있습니다.&lt;/p&gt;
&lt;h1 id=&quot;4cf1&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;Are Microservices a terrible idea?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&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; (147개의 파이프라인을 즐기세요) &amp;mdash; 독립적인 개발 팀을 포함하여, 이런저런 것들.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;독립적인 확장성&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관심사의 명확한 분리&lt;/b&gt; &amp;mdash; 이것은 원칙을 준수하는 강력한 개발 팀으로 대체할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 그들은 많은 복잡성을 추가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 당신이 &lt;b&gt;일을 끝내는&lt;/b&gt; 종류의 개발자라면 &amp;mdash; 그리고 그래야 한다고 생각합니다 &amp;mdash; 복잡성을 추가하는 것은 항상 강력한 이유가 필요합니다.&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;h1 id=&quot;7d9c&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 모놀리식 구조로 시작하세요. 큰 범위의 테스트를 잘 수행하고, 경계에 집착하세요. 모놀리식 경계를 마이크로서비스처럼 취급하며, API가 아닌 인터페이스를 통해 상호작용하도록 하세요. 경계를 나눌 필요성이 생길 때까지는 나누지 마세요. 배포성, 확장성, 독립적인 팀 작업에 대한 명확한 이유가 있을 때만 나누고, 테스트 수준을 유지할 방법을 구체적으로 문서화하세요. 좋은 이유가 있으면 진행하고, 그렇지 않으면 모놀리식 구조를 유지하세요.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742126</guid>
      <comments>https://sojw.tistory.com/1169742126#entry1169742126comment</comments>
      <pubDate>Fri, 25 Oct 2024 11:08:29 +0900</pubDate>
    </item>
    <item>
      <title>System Design &amp;mdash; Tips</title>
      <link>https://sojw.tistory.com/1169742125</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/javarevisited/system-design-tips-62c26366cf48&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/javarevisited/system-design-tips-62c26366cf48&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728547682634&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;System Design &amp;mdash; Tips&quot; data-og-description=&quot;Designing a robust and scalable system involves careful planning and consideration of various factors. Here are some essential tips to&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/javarevisited/system-design-tips-62c26366cf48&quot; data-og-url=&quot;https://medium.com/javarevisited/system-design-tips-62c26366cf48&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/4l0ed/hyXd8UpiAX/ajBrJXIM3dMe7QXd0X0ps1/img.jpg?width=1200&amp;amp;height=821&amp;amp;face=354_195_468_309&quot;&gt;&lt;a href=&quot;https://medium.com/javarevisited/system-design-tips-62c26366cf48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/javarevisited/system-design-tips-62c26366cf48&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/4l0ed/hyXd8UpiAX/ajBrJXIM3dMe7QXd0X0ps1/img.jpg?width=1200&amp;amp;height=821&amp;amp;face=354_195_468_309');&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;System Design &amp;mdash; Tips&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Designing a robust and scalable system involves careful planning and consideration of various factors. Here are some essential tips to&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;/p&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;&lt;b&gt;기능적 요구 사항&lt;/b&gt;: 시스템이 수행해야 할 기능 및 특징.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비기능적 요구 사항&lt;/b&gt;: 성능, 확장성, 보안, 가용성 등.&lt;/li&gt;
&lt;/ul&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;b&gt;모놀리식 vs. 마이크로서비스&lt;/b&gt;: 하나의 큰 애플리케이션으로 만들지, 마이크로서비스로 분할할지 결정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;계층형 아키텍처&lt;/b&gt;: 프레젠테이션, 애플리케이션, 비즈니스, 데이터 계층 등으로 나누어 관심사를 분리합니다.&lt;/li&gt;
&lt;/ul&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;&lt;b&gt;수평 확장(Horizontal Scaling)&lt;/b&gt;: 서버를 추가하여 부하를 처리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;수직 확장(Vertical Scaling)&lt;/b&gt;: 기존 서버에 더 많은 자원(CPU, RAM)을 추가합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로드 밸런싱&lt;/b&gt;: 트래픽을 여러 서버에 분산시켜 특정 서버가 과부하되지 않도록 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 데이터베이스 설계&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;정규화 vs. 비정규화&lt;/b&gt;: 중복을 줄이는 정규화와 읽기 성능을 높이는 비정규화 사이의 균형을 맞춥니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;적절한 데이터베이스 선택&lt;/b&gt;: 관계형 데이터에는 SQL, 비정형 데이터에는 NoSQL을 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;샤딩(Sharding)&lt;/b&gt;: 대규모 데이터와 높은 트래픽을 처리하기 위해 데이터를 여러 데이터베이스로 분산합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;락 메커니즘&lt;/b&gt;: 낙관적/비관적 동시성 제어를 사용하여 데이터 충돌을 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 분산 락&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;: 프로세스가 크래시될 때를 대비해 락에 TTL(수명)을 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;갱신 메커니즘&lt;/b&gt;: 락을 보유한 프로세스가 더 많은 시간이 필요할 경우 갱신할 수 있게 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Redis&lt;/b&gt;: SETNX 명령어를 사용해 간단한 락 메커니즘 구현.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Zookeeper &amp;amp; Etcd&lt;/b&gt;: 강력한 일관성 보장을 위한 복잡한 분산 락 시스템.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 분산 캐싱&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;&lt;b&gt;CDN&lt;/b&gt;: 콘텐츠 전송 네트워크를 사용하여 정적 콘텐츠를 사용자에게 더 가까운 곳에서 제공.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파티셔닝&lt;/b&gt;: 높은 처리량을 위해 데이터를 여러 파티션 또는 샤드로 분산.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 장애 내성 및 고가용성&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;&lt;b&gt;페일오버 메커니즘&lt;/b&gt;: 장애 발생 시 대기 시스템으로 자동 전환.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;백업 및 복구&lt;/b&gt;: 데이터를 정기적으로 백업하고 복구 계획을 마련합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 보안&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;&lt;b&gt;암호화&lt;/b&gt;: 중요한 정보를 보호하기 위해 데이터 저장 및 전송 중에 암호화를 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방화벽 및 침입 탐지&lt;/b&gt;: 네트워크 보안 조치를 통해 비인가 접근을 탐지하고 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. 모니터링 및 로깅&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;&lt;b&gt;로깅&lt;/b&gt;: 시스템의 동작을 분석하고 디버깅할 수 있도록 로그를 유지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. API 및 통신&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;RESTful API&lt;/b&gt;: 웹 서비스 확장성과 무상태 통신을 위해 REST를 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메시지 큐&lt;/b&gt;: 서비스 간 비동기 통신을 위해 RabbitMQ, Kafka와 같은 메시지 큐를 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11. 개발 모범 사례&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;: Git과 같은 버전 관리 시스템을 사용하여 변경 사항을 추적하고 협업합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CI/CD(지속적 통합/지속적 배포)&lt;/b&gt;: 테스트와 배포를 자동화하여 빠르고 신뢰성 있는 업데이트를 제공합니다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742125</guid>
      <comments>https://sojw.tistory.com/1169742125#entry1169742125comment</comments>
      <pubDate>Thu, 10 Oct 2024 17:09:20 +0900</pubDate>
    </item>
    <item>
      <title>Throttling Design Pattern to Handle an Extreme Load</title>
      <link>https://sojw.tistory.com/1169742124</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@dmosyan/throttling-design-pattern-to-handle-an-extreme-load-a0b24c31e3ec&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@dmosyan/throttling-design-pattern-to-handle-an-extreme-load-a0b24c31e3ec&lt;/a&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;리소스 소비 제어는 애플리케이션이나 서비스가 과도한 부하가 걸릴 때에도 시스템이 계속 작동하고 SLA(서비스 수준 협약)를 충족할 수 있게 해줍니다. 애플리케이션의 부하는 시간에 따라, 활성 사용자 수나 그들이 수행하는 활동의 종류에 따라 달라집니다. 만약 시스템의 처리 요구 사항이 사용 가능한 리소스 용량을 초과하면 성능 저하나 시스템 오류가 발생할 수 있습니다. 이를 해결하기 위해 클라우드에서는 여러 전략을 사용할 수 있으며, 그 중 하나가 자동 확장(autoscaling)을 통해 사용자의 요구에 맞게 리소스를 동적으로 조정하는 것입니다. 이 방법은 사용자 수요를 충족시키면서도 비용을 최적화할 수 있습니다.&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;이를 해결하기 위한 대안 전략은 애플리케이션이 리소스를 일정 한도까지만 사용하도록 하고, 이 한도에 도달하면 요청을 제한하는 방식(스로틀링, throttling)을 사용하는 것입니다. 시스템은 리소스 사용을 모니터링하여 임계값을 초과하면 특정 사용자나 요청을 제한할 수 있어야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&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;: 특정 사용자가 정해진 시간 동안 시스템 API를 초과해 요청하면 요청을 거부하는 방식입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비필수 서비스의 기능 제한&lt;/b&gt;: 중요한 서비스가 충분한 리소스를 확보하도록 비필수 기능을 비활성화하거나 기능을 저하시키는 방법입니다. 예를 들어, 스트리밍 서비스는 해상도를 낮출 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부하 평준화&lt;/b&gt;: 우선 순위 대기열(priority queue)을 사용하여 SLA가 높은 테넌트의 요청은 즉시 처리하고, 그 외의 요청은 대기시키는 방식입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3rd-party 서비스 통합 시 주의 사항&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 서비스가 비활성화되거나 오류를 반환할 수 있으므로, 동시 요청 수를 줄여 오류 로그가 불필요하게 많이 쌓이지 않도록 해야 합니다. 성공적으로 처리된 후에는 다시 정상적인 요청 처리로 돌아갈 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자동 확장과 스로틀링의 조합&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 확장과 스로틀링을 결합하면 애플리케이션이 높은 수요 속에서도 SLA를 유지할 수 있습니다. 높은 수요가 지속될 것으로 예상되면 스로틀링을 임시적으로 사용하여 시스템이 확장될 시간을 확보할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&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;스로틀링은 빠르게 이루어져야 하며, 로드가 완화되면 원래 상태로 신속히 돌아가야 합니다.&lt;/li&gt;
&lt;li&gt;스로틀링 중인 서비스가 사용자 요청을 거부할 때는 429(&amp;ldquo;Too many requests&amp;rdquo;) 또는 503(&amp;ldquo;Server Too Busy&amp;rdquo;)와 같은 오류 코드를 반환해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용 시기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SLA를 유지하기 위해.&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;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;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742124</guid>
      <comments>https://sojw.tistory.com/1169742124#entry1169742124comment</comments>
      <pubDate>Thu, 10 Oct 2024 16:59:24 +0900</pubDate>
    </item>
    <item>
      <title>How to Prevent Duplicate Requests Effectively</title>
      <link>https://sojw.tistory.com/1169742123</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/javarevisited/rest-api-how-to-prevent-duplicate-requests-effectively-d3be88ef7838&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/javarevisited/rest-api-how-to-prevent-duplicate-requests-effectively-d3be88ef7838&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728471366993&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;Rest API: How to Prevent Duplicate Requests Effectively&quot; data-og-description=&quot;The solution to prevent duplicate requests that I want to talk about here is that when a user manipulates an API feed&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/javarevisited/rest-api-how-to-prevent-duplicate-requests-effectively-d3be88ef7838&quot; data-og-url=&quot;https://medium.com/javarevisited/rest-api-how-to-prevent-duplicate-requests-effectively-d3be88ef7838&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b0WPHw/hyXd3rN8Q0/d8Z582EjlHzn7OukgFPPvk/img.png?width=676&amp;amp;height=303&amp;amp;face=0_0_676_303&quot;&gt;&lt;a href=&quot;https://medium.com/javarevisited/rest-api-how-to-prevent-duplicate-requests-effectively-d3be88ef7838&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/javarevisited/rest-api-how-to-prevent-duplicate-requests-effectively-d3be88ef7838&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b0WPHw/hyXd3rN8Q0/d8Z582EjlHzn7OukgFPPvk/img.png?width=676&amp;amp;height=303&amp;amp;face=0_0_676_303');&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;Rest API: How to Prevent Duplicate Requests Effectively&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The solution to prevent duplicate requests that I want to talk about here is that when a user manipulates an API feed&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;b&gt;구현 아이디어&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;사용자가 API를 호출할 때, 요청 본문(Request Body)에서 특정 데이터를 추출하여 Redis 키를 생성합니다.&lt;/li&gt;
&lt;li&gt;이 키는 MD5로 해시되어 저장되며, Redis에 키가 이미 존재하는지 여부를 확인합니다.&lt;/li&gt;
&lt;li&gt;만약 Redis에 키가 존재하면 중복 요청으로 간주하고 오류를 반환합니다.&lt;/li&gt;
&lt;li&gt;키가 존재하지 않으면 Redis에 새로운 키를 저장하고, 이 키는 일정 시간이 지나면 만료됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구현 순서&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;특정 필드(예: productId, transactionId)를 기반으로 Redis 키를 생성하고, 필요 시 옵션 값을 추가하여 유연하게 중복 요청을 방지할 수 있도록 합니다.&lt;/li&gt;
&lt;li&gt;생성된 키는 MD5로 해시하여 저장하고, 키의 유효 시간(예: 40초)을 설정합니다.&lt;/li&gt;
&lt;li&gt;중복 요청이 발생하면 DuplicationException을 발생시켜 클라이언트에 오류 메시지를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 클래스 및 설명&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;PreventDuplicateValidator : 중복 요청 방지를 위한 커스텀 어노테이션. 필드 목록과 키 만료 시간을 설정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;PreventDuplicateValidatorAspect : 어노테이션에 지정된 필드를 기준으로 Redis 키를 생성하고, 중복 요청을 확인하는 로직을 구현합니다.&lt;/li&gt;
&lt;li&gt;Utils : 요청 본문을 추출하고 MD5 해시를 생성하는 유틸리티 클래스입니다.&lt;/li&gt;
&lt;li&gt;HandleGlobalException : 중복 요청 발생 시 던져진 DuplicationException을 처리하여 클라이언트에 적절한 오류 메시지를 반환합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테스트&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;Postman을 사용하여 API 요청을 보냅니다. 첫 번째 요청은 성공적으로 처리되고 Redis에 키가 저장됩니다.&lt;/li&gt;
&lt;li&gt;두 번째로 동일한 요청을 보내면 Redis에 키가 이미 존재하므로 중복 요청으로 처리되고 오류 메시지가 반환됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론&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;중복 요청 방지를 위해 어떤 필드를 사용할지 신중히 선택해야 합니다.&lt;/li&gt;
&lt;li&gt;키의 만료 시간을 비즈니스 요구사항에 맞게 조정할 필요가 있습니다.&lt;/li&gt;
&lt;li&gt;성능 최적화를 위해 MD5 해시 사용 여부를 고려해야 합니다.&lt;/li&gt;
&lt;/ul&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>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742123</guid>
      <comments>https://sojw.tistory.com/1169742123#entry1169742123comment</comments>
      <pubDate>Wed, 9 Oct 2024 19:57:37 +0900</pubDate>
    </item>
    <item>
      <title>Optimizing Java App Performance by understanding JVM Architechture</title>
      <link>https://sojw.tistory.com/1169742122</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@kiarash.shamaii/optimizing-java-app-performance-by-understanding-jvm-architechture-7bd32eeac520&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@kiarash.shamaii/optimizing-java-app-performance-by-understanding-jvm-architechture-7bd32eeac520&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728400011386&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;Optimizing Java App Performance by understanding JVM Architechture&quot; data-og-description=&quot;As Java developers, we&amp;rsquo;re often tasked with building high-performance applications that can handle demanding workloads and provide a&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@kiarash.shamaii/optimizing-java-app-performance-by-understanding-jvm-architechture-7bd32eeac520&quot; data-og-url=&quot;https://medium.com/@kiarash.shamaii/optimizing-java-app-performance-by-understanding-jvm-architechture-7bd32eeac520&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/blckLB/hyXd7tYNFf/VOohzyFqMS0Bu8ArQUonH1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/blgTLa/hyXd6aLafM/wcETOc5JAu1IKr6YKFt0Lk/img.png?width=989&amp;amp;height=742&amp;amp;face=0_0_989_742,https://scrap.kakaocdn.net/dn/HMcHH/hyXd6IAGsc/81PkmzTH1KKpeK6vuUQnn1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600&quot;&gt;&lt;a href=&quot;https://medium.com/@kiarash.shamaii/optimizing-java-app-performance-by-understanding-jvm-architechture-7bd32eeac520&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@kiarash.shamaii/optimizing-java-app-performance-by-understanding-jvm-architechture-7bd32eeac520&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/blckLB/hyXd7tYNFf/VOohzyFqMS0Bu8ArQUonH1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/blgTLa/hyXd6aLafM/wcETOc5JAu1IKr6YKFt0Lk/img.png?width=989&amp;amp;height=742&amp;amp;face=0_0_989_742,https://scrap.kakaocdn.net/dn/HMcHH/hyXd6IAGsc/81PkmzTH1KKpeK6vuUQnn1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600');&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;Optimizing Java App Performance by understanding JVM Architechture&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;As Java developers, we&amp;rsquo;re often tasked with building high-performance applications that can handle demanding workloads and provide a&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;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;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;: 객체가 더 이상 필요 없는데도 메모리에서 해제되지 않으면 힙 메모리가 계속 커져서 시스템이 느려지고, 결국 메모리 부족으로 애플리케이션이 비정상 종료될 수 있습니다. 이를 방지하기 위해 Eclipse Memory Analyzer(MAT)나 JProfiler 같은 도구를 사용해 메모리 사용 현황을 분석합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체 생명주기 최적화&lt;/b&gt;: 객체가 필요 없어지면 참조를 명확히 해제해야 합니다. try-with-resources 같은 기능을 활용하면 자원을 자동으로 해제할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가비지 컬렉션 튜닝&lt;/b&gt;: JVM의 가비지 컬렉터는 더 이상 사용되지 않는 객체를 메모리에서 해제하는 역할을 합니다. G1GC 같은 최신 가비지 컬렉터를 사용해 성능을 최적화하고, GC가 실행되는 동안 애플리케이션의 정지 시간을 줄일 수 있습니다. 예를 들어, -Xms(초기 힙 크기)와 -Xmx(최대 힙 크기) 옵션을 조정하여 애플리케이션이 사용할 수 있는 메모리 양을 최적화합니다.&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;b&gt;불필요한 잠금 제거&lt;/b&gt;: 자바의 멀티스레딩 기능을 통해 병렬 처리가 가능하지만, 불필요한 동기화나 잠금이 있으면 성능 저하가 발생할 수 있습니다. 잠금이 필요한 부분을 최소화하고, 경합을 피할 수 있는 방안을 모색해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스레드 풀 사용&lt;/b&gt;: 새로운 작업마다 새로운 스레드를 생성하면 성능이 저하될 수 있으므로, 일정한 개수의 스레드로 작업을 처리하는 스레드 풀을 사용하는 것이 좋습니다. 예를 들어 Executors.newFixedThreadPool()로 고정된 크기의 스레드 풀을 생성하여 여러 작업을 처리하고, 작업이 끝나면 풀을 종료합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;블로킹 작업 피하기&lt;/b&gt;: I/O 또는 데이터베이스 작업처럼 오래 걸리는 블로킹 작업은 애플리케이션의 스레드를 정지시킬 수 있습니다. 비동기 작업이나 비블로킹 I/O를 사용하면 이러한 문제를 해결할 수 있습니다.&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;애플리케이션의 성능을 지속적으로 모니터링하는 것은 매우 중요합니다. CPU 사용률, 힙 메모리 사용량, 스레드 상태, 응답 시간, 처리량 등의 주요 지표를 모니터링해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Java Flight Recorder(JFR)&lt;/b&gt; 같은 도구를 사용하면 이러한 성능 지표를 실시간으로 모니터링하고 문제를 식별할 수 있습니다. 예를 들어, VisualVM을 통해 애플리케이션의 메모리 사용량, 스레드 활동, 가비지 컬렉션 빈도 등을 시각적으로 확인하고 분석할 수 있습니다.&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;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>emotional developer/detect-Java</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742122</guid>
      <comments>https://sojw.tistory.com/1169742122#entry1169742122comment</comments>
      <pubDate>Wed, 9 Oct 2024 00:16:49 +0900</pubDate>
    </item>
    <item>
      <title>E-commerce Platform like Amazon</title>
      <link>https://sojw.tistory.com/1169742121</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@kevinchwong/e-commerce-platform-like-amazon-6adf3be577fd&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@kevinchwong/e-commerce-platform-like-amazon-6adf3be577fd&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&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;2000&quot; data-origin-height=&quot;1278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKKuIK/btsJYakNVyC/YR6RF6cdZQMndOtr0ovRM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKKuIK/btsJYakNVyC/YR6RF6cdZQMndOtr0ovRM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKKuIK/btsJYakNVyC/YR6RF6cdZQMndOtr0ovRM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKKuIK%2FbtsJYakNVyC%2FYR6RF6cdZQMndOtr0ovRM0%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;2000&quot; height=&quot;1278&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1278&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;&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;사용자는 웹 애플리케이션을 통해 제품을 탐색하며, CDN을 통해 정적 콘텐츠와 캐시된 데이터를 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;API 게이트웨이 및 로드 밸런서&lt;/b&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;/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;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;li&gt;&lt;b&gt;재고 서비스&lt;/b&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742121</guid>
      <comments>https://sojw.tistory.com/1169742121#entry1169742121comment</comments>
      <pubDate>Tue, 8 Oct 2024 23:52:43 +0900</pubDate>
    </item>
    <item>
      <title>Pessimistic Locking in Distributed Systems</title>
      <link>https://sojw.tistory.com/1169742120</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@_sidharth_m_/how-distributed-systems-avoid-race-conditions-using-pessimistic-locking-1dc112a82b5e&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@_sidharth_m_/how-distributed-systems-avoid-race-conditions-using-pessimistic-locking-1dc112a82b5e&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728385079350&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;How Distributed Systems Avoid Race Conditions using Pessimistic Locking?&quot; data-og-description=&quot;Understanding Pessimistic Locks, Leases, and Fence Tokens in Distributed Systems&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@_sidharth_m_/how-distributed-systems-avoid-race-conditions-using-pessimistic-locking-1dc112a82b5e&quot; data-og-url=&quot;https://medium.com/@_sidharth_m_/how-distributed-systems-avoid-race-conditions-using-pessimistic-locking-1dc112a82b5e&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/foApm/hyXd3dYQhg/Ue05bzgqROP0eHStHZxgJk/img.jpg?width=937&amp;amp;height=559&amp;amp;face=0_0_937_559&quot;&gt;&lt;a href=&quot;https://medium.com/@_sidharth_m_/how-distributed-systems-avoid-race-conditions-using-pessimistic-locking-1dc112a82b5e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@_sidharth_m_/how-distributed-systems-avoid-race-conditions-using-pessimistic-locking-1dc112a82b5e&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/foApm/hyXd3dYQhg/Ue05bzgqROP0eHStHZxgJk/img.jpg?width=937&amp;amp;height=559&amp;amp;face=0_0_937_559');&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;How Distributed Systems Avoid Race Conditions using Pessimistic Locking?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Understanding Pessimistic Locks, Leases, and Fence Tokens in Distributed Systems&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;잠금을 획득하는 것만으로는 충분하지 않습니다&lt;/b&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;문제를&amp;nbsp;해결하기&amp;nbsp;위해&amp;nbsp;노드가&amp;nbsp;잠금을&amp;nbsp;획득할&amp;nbsp;때마다&amp;nbsp;잠금&amp;nbsp;데이터베이스&amp;nbsp;레코드에&amp;nbsp;잠금에&amp;nbsp;대한&amp;nbsp;임대&amp;nbsp;기간이라고도&amp;nbsp;하는&amp;nbsp;TTL(Time&amp;nbsp;to&amp;nbsp;Live)이&amp;nbsp;설정됩니다.&amp;nbsp;임대가&amp;nbsp;만료되면&amp;nbsp;처음에&amp;nbsp;잠금을&amp;nbsp;획득한&amp;nbsp;노드가&amp;nbsp;업데이트를&amp;nbsp;완료했는지&amp;nbsp;여부에&amp;nbsp;관계없이&amp;nbsp;공유&amp;nbsp;리소스에&amp;nbsp;대한&amp;nbsp;잠금이&amp;nbsp;해제됩니다.&amp;nbsp;이를&amp;nbsp;통해&amp;nbsp;시스템은&amp;nbsp;노드가&amp;nbsp;장애로&amp;nbsp;인해&amp;nbsp;잠금을&amp;nbsp;해제하지&amp;nbsp;못하는&amp;nbsp;시나리오를&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;937&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b82xIA/btsJX9MVxRd/qrCfJCuBQCW1zxoVjMkihK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b82xIA/btsJX9MVxRd/qrCfJCuBQCW1zxoVjMkihK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b82xIA/btsJX9MVxRd/qrCfJCuBQCW1zxoVjMkihK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb82xIA%2FbtsJX9MVxRd%2FqrCfJCuBQCW1zxoVjMkihK%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;937&quot; height=&quot;559&quot; data-origin-width=&quot;937&quot; data-origin-height=&quot;559&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;913&quot; data-origin-height=&quot;591&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pRKWh/btsJYadWhdv/qAWSvV7EIexq7P4wpBukv0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pRKWh/btsJYadWhdv/qAWSvV7EIexq7P4wpBukv0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pRKWh/btsJYadWhdv/qAWSvV7EIexq7P4wpBukv0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpRKWh%2FbtsJYadWhdv%2FqAWSvV7EIexq7P4wpBukv0%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;913&quot; height=&quot;591&quot; data-origin-width=&quot;913&quot; data-origin-height=&quot;591&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #242b34; text-align: start;&quot;&gt;노드가 실패하지 않고 일시 정지되었다가 다시 시작됨&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242b34; text-align: start;&quot;&gt;이제 임대가 있는 잠금이 있으므로, 노드 A가 임대가 있는 잠금을 획득한 후 공유 리소스를 업데이트하기 전에 어떤 이유로든 일시 중지하거나 동결하는 시나리오를 상상해 보겠습니다. 이 동결 기간 동안 임대가 만료되고 나머지 시스템에 대한 잠금이 해제됩니다. 다른 노드(예: 노드 B)가 공유 리소스에 대한 이 잠금을 획득하고 그 값을 업데이트합니다. 노드 B가 리소스를 업데이트하면 노드 A는 자신이 여전히 잠금을 소유하고 있다고 생각하여 리소스에 업데이트를 푸시하여 노드 B의 업데이트를 덮어씁니다. 이렇게 되면 공유 데이터 리소스가 잘못된 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&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;926&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YMR9Z/btsJY6ILCrm/GuxIFIp8KVOKveCzt7VWOK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YMR9Z/btsJY6ILCrm/GuxIFIp8KVOKveCzt7VWOK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YMR9Z/btsJY6ILCrm/GuxIFIp8KVOKveCzt7VWOK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYMR9Z%2FbtsJY6ILCrm%2FGuxIFIp8KVOKveCzt7VWOK%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;926&quot; height=&quot;630&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;펜스&amp;nbsp;토큰&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;문제를&amp;nbsp;해결하려면&amp;nbsp;시스템의&amp;nbsp;각&amp;nbsp;노드가&amp;nbsp;공유&amp;nbsp;데이터&amp;nbsp;리소스에&amp;nbsp;대한&amp;nbsp;쓰기&amp;nbsp;요청과&amp;nbsp;함께&amp;nbsp;새&amp;nbsp;펜싱&amp;nbsp;토큰을&amp;nbsp;보내야&amp;nbsp;합니다.&amp;nbsp;공유&amp;nbsp;데이터&amp;nbsp;리소스는&amp;nbsp;이미&amp;nbsp;최신&amp;nbsp;펜싱&amp;nbsp;토큰을&amp;nbsp;확인한&amp;nbsp;경우&amp;nbsp;이전&amp;nbsp;펜싱&amp;nbsp;토큰을&amp;nbsp;거부합니다.&amp;nbsp;간단히&amp;nbsp;설명하자면,&amp;nbsp;이&amp;nbsp;펜싱&amp;nbsp;토큰은&amp;nbsp;공유&amp;nbsp;리소스에&amp;nbsp;대한&amp;nbsp;잠금이&amp;nbsp;요청될&amp;nbsp;때마다&amp;nbsp;잠금&amp;nbsp;데이터베이스가&amp;nbsp;증가시키는&amp;nbsp;숫자일&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전&amp;nbsp;시나리오에서는&amp;nbsp;노드&amp;nbsp;A가&amp;nbsp;잠금을&amp;nbsp;획득할&amp;nbsp;때&amp;nbsp;펜싱&amp;nbsp;토큰&amp;nbsp;값&amp;nbsp;10을&amp;nbsp;할당받았고,&amp;nbsp;노드&amp;nbsp;A가&amp;nbsp;동결된&amp;nbsp;후&amp;nbsp;노드&amp;nbsp;B가&amp;nbsp;잠금을&amp;nbsp;획득할&amp;nbsp;때&amp;nbsp;펜싱&amp;nbsp;토큰&amp;nbsp;값&amp;nbsp;11을&amp;nbsp;제공받았습니다.&amp;nbsp;노드&amp;nbsp;B가&amp;nbsp;업데이트를&amp;nbsp;실행했으므로&amp;nbsp;공유&amp;nbsp;데이터&amp;nbsp;자원은&amp;nbsp;이미&amp;nbsp;펜싱&amp;nbsp;토큰&amp;nbsp;값&amp;nbsp;11을&amp;nbsp;보게&amp;nbsp;됩니다.&amp;nbsp;따라서&amp;nbsp;노드&amp;nbsp;A의&amp;nbsp;펜싱&amp;nbsp;토큰이&amp;nbsp;(노드&amp;nbsp;A&amp;nbsp;이후에&amp;nbsp;잠금을&amp;nbsp;획득한)&amp;nbsp;노드&amp;nbsp;B보다&amp;nbsp;작으므로&amp;nbsp;재개된&amp;nbsp;후&amp;nbsp;A가&amp;nbsp;보낸&amp;nbsp;업데이트를&amp;nbsp;거부하게&amp;nbsp;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&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;913&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t04VB/btsJXSq7UUr/u2tX4CCilQnDKQ36qB7zq0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t04VB/btsJXSq7UUr/u2tX4CCilQnDKQ36qB7zq0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t04VB/btsJXSq7UUr/u2tX4CCilQnDKQ36qB7zq0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft04VB%2FbtsJXSq7UUr%2Fu2tX4CCilQnDKQ36qB7zq0%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;913&quot; height=&quot;618&quot; data-origin-width=&quot;913&quot; data-origin-height=&quot;618&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;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;&lt;b&gt;다른 post 참고&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728385207651&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;How to do distributed locking &amp;mdash; Martin Kleppmann&amp;rsquo;s blog&quot; data-og-description=&quot;How to do distributed locking Published by Martin Kleppmann on 08 Feb 2016. As part of the research for my book, I came across an algorithm called Redlock on the Redis website. The algorithm claims to implement fault-tolerant distributed locks (or rather, &quot; data-og-host=&quot;martin.kleppmann.com&quot; data-og-source-url=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot; data-og-url=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gPSyw/hyXd5CSf5S/LvKpG4VALoh8D7pv39xik1/img.png?width=1100&amp;amp;height=400&amp;amp;face=0_0_1100_400,https://scrap.kakaocdn.net/dn/b6tQyG/hyXd2lQQOu/czxT1F7PAW43Uq6FyNbQy0/img.png?width=1100&amp;amp;height=400&amp;amp;face=0_0_1100_400&quot;&gt;&lt;a href=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gPSyw/hyXd5CSf5S/LvKpG4VALoh8D7pv39xik1/img.png?width=1100&amp;amp;height=400&amp;amp;face=0_0_1100_400,https://scrap.kakaocdn.net/dn/b6tQyG/hyXd2lQQOu/czxT1F7PAW43Uq6FyNbQy0/img.png?width=1100&amp;amp;height=400&amp;amp;face=0_0_1100_400');&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;How to do distributed locking &amp;mdash; Martin Kleppmann&amp;rsquo;s blog&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;How to do distributed locking Published by Martin Kleppmann on 08 Feb 2016. As part of the research for my book, I came across an algorithm called Redlock on the Redis website. The algorithm claims to implement fault-tolerant distributed locks (or rather,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;martin.kleppmann.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>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742120</guid>
      <comments>https://sojw.tistory.com/1169742120#entry1169742120comment</comments>
      <pubDate>Tue, 8 Oct 2024 23:42:22 +0900</pubDate>
    </item>
    <item>
      <title>k8s JVM memory Config</title>
      <link>https://sojw.tistory.com/1169742119</link>
      <description>&lt;h2&gt;개요&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Pod total memory 대비 JVM memory 설정값 측정&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Pod total memory&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Pod에 지정 된 limit memory 값&lt;/li&gt;
&lt;li&gt;ex) 2000M&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Pod OS 기본 사용 memory&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Pod 구동 시, 기본적으로 사용하는 memory&lt;/li&gt;
&lt;li&gt;대략 200M 가정 ( 대체로 200M가 보다 더 작을 것이지만, 여유롭게 가정)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;JVM memory&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;JVM total memory = heap + metaspace&lt;ul&gt;
&lt;li&gt;ex) 예제 가정값&lt;/li&gt;
&lt;li&gt;Pod total memory: 2000M&lt;/li&gt;
&lt;li&gt;metaspace: 256M&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pod total memory 대비 JVM memory Max 사용량 비율&lt;ul&gt;
&lt;li&gt;(Pod total memory * heap 사용 비율) + metaspace = JVM total memory → Pod total memory 대비 사용 비율&lt;/li&gt;
&lt;li&gt;(2000 * 0.5) + 256 = 1256 -&amp;gt; 62.8%&lt;/li&gt;
&lt;li&gt;(2000 * 0.6) + 256 = 1456 -&amp;gt; 72.8%&lt;/li&gt;
&lt;li&gt;(2000 * 0.7) + 256 = 1656 -&amp;gt; 82.8%&lt;/li&gt;
&lt;li&gt;(2000 * 0.8) + 256 = 1856 -&amp;gt; 92.8%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;JVM memory 사용 비율 계산&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Pod total memory(- OS 기본 메모리 제외)의 75% 까지 이용&lt;ul&gt;
&lt;li&gt;k8s OOM killer 대상에서 제외 되게끔&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ex)&lt;ul&gt;
&lt;li&gt;((Pod total memory - Pod OS 기본 사용 memory) * 0.75) = metaspace + (Pod total memory* heap 사용 비율) → heap 사용 비율 계산&lt;/li&gt;
&lt;li&gt;((2000 - 200) * 0.75) = 256 + (2000 * x), x(heap 사용 비율) → 55%&lt;/li&gt;
&lt;li&gt;((4000 - 200) * 0.75) = 256 - (4000 * x), x(heap 사용 비율) → 65%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742119</guid>
      <comments>https://sojw.tistory.com/1169742119#entry1169742119comment</comments>
      <pubDate>Wed, 19 Jun 2024 16:41:48 +0900</pubDate>
    </item>
    <item>
      <title>6 Tips for Resolving Common Java Performance Problems</title>
      <link>https://sojw.tistory.com/1169742118</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://medium.com/javarevisited/6-tips-for-resolving-common-java-performance-problems-b88f42dc6118&quot;&gt;https://medium.com/javarevisited/6-tips-for-resolving-common-java-performance-problems-b88f42dc6118&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;6 Common Java performance problems&lt;/h2&gt;
&lt;h3&gt;1. Memory leaks&lt;/h3&gt;
&lt;p&gt;자바는 가비지 컬렉터를 통해 자동 메모리 관리를 제공함에도 불구하고, 성능 문제에 대한 보장을 하지 않습니다. 가비지 컬렉터는 더 이상 사용되지 않는 메모리를 자동으로 식별하고 회수하지만, 자동 메모리 관리에만 의존하는 것은 성능 문제에서 완벽한 방법은 아닙니다.&lt;/p&gt;
&lt;p&gt;자바의 가비지 컬렉터는 더 이상 사용되지 않는 메모리를 자동으로 식별하고 회수하여 언어의 강력한 메모리 관리 시스템의 필수적인 기능 입니다.&lt;/p&gt;
&lt;p&gt;그러나 이러한 고급 메커니즘을 사용하더라도, 심지어 가장 숙련된 프로그래머들도 자바 메모리 누수를 우연히 발생시킬 수 있습니다. 메모리 누수는 객체가 의도치 않게 메모리에 유지되어 가비지 컬렉터가 관련 메모리를 회수하지 못하게 하는 것으로, 시간이 지남에 따라 메모리 소비가 증가하고 응용 프로그램의 성능이 저하될 수 있습니다.&lt;/p&gt;
&lt;p&gt;메모리 누수는 겹치는 증상 때문에 감지하고 해결하기 어려울 수 있습니다. 우리의 경우, 가장 명백한 증상 중 하나인 OutOfMemoryError 힙 오류가 있었으며, 시간이 지남에 따라 성능이 저하되었습니다.&lt;/p&gt;
&lt;p&gt;자바에서 메모리 누수를 일으킬 수 있는 여러 가지 문제가 있습니다. 우리의 첫 번째 접근 방식은 이것이 정상적인 메모리 고갈(디자인의 부적절한 결과로 인한)인지 누수인지를 분석하여 메모리 부족 오류 메시지를 조사하는 것이었습니다.&lt;/p&gt;
&lt;p&gt;우리는 먼저, static 필드, 컬렉션 및 애플리케이션의 전체 수명 동안 중요한 메모리를 차단할 수 있는 정적으로 선언된 큰 객체와 같은 가장 가능성이 높은 원인들을 확인하는 것으로 시작했습니다.&lt;/p&gt;
&lt;p&gt;예를 들어, 아래의 코드 예제에서는 리스트를 초기화할 때 static 키워드를 제거하면 메모리 사용량이 급격하게 감소합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;
public class StaticFieldsMemoryTestExample {
    public static List&amp;lt;Double&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();
    public void addToList() {
        for (int i = 0; i &amp;lt; 10000000; i++) {
            list.add(Math.random());
        }
        Log.info(&amp;quot;Debug Point 2&amp;quot;);
    }
    public static void main(String[] args) {
        new StaticFieldsDemo().addToList();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;우리가 취한 다른 조치에는 메모리를 차단할 수 있는 열린 리소스나 연결을 확인하는 것이 포함되었습니다. 이에 따라 가비지 컬렉터의 도달 범위 밖에 있습니다. HashMaps와 HashSets에서 equals() 및 hashCode() 메서드의 잘못된 구현을 수정하여 적절한 equals() 및 hashCode() 메서드를 작성했습니다. 다음은 equals() 및 hashCode() 메서드를 올바르게 구현하는 예시입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public class Person {
    public String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof Person)) {
            return false;
        }
        Person person = (Person) o;
        return person.name.equals(name);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + name.hashCode();
        return result;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Memory leaks를 방지하는 tips&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;코드가 파일 핸들, 데이터베이스 연결 또는 네트워크 소켓과 같은 외부 리소스를 사용하는 경우, 해당 리소스가 더 이상 필요하지 않을 때 명시적으로 해제하십시오.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;VisualVM이나 YourKit과 같은 메모리 프로파일링 도구를 사용하여 응용 프로그램에서 잠재적인 메모리 누수를 분석하고 식별하십시오.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;싱글톤을 사용할 때, 싱글톤이 실제로 필요할 때까지 불필요한 리소스 할당을 피하기 위해 이른 초기화(eager loading) 대신 지연 로딩(lazy loading)을 사용하십시오.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;코드가 파일 핸들, 데이터베이스 연결 또는 네트워크 소켓과 같은 외부 리소스를 사용하는 경우, 해당 리소스가 더 이상 필요하지 않을 때 명시적으로 해제하십시오.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Thread deadlocks&lt;/h3&gt;
&lt;p&gt;자바는 멀티쓰레드 언어입니다. 이것은 자바를 특히 복수의 작업을 동시에 처리하는 기업 애플리케이션을 개발하기에 적합한 언어로 만드는 기능 중 하나입니다.&lt;/p&gt;
&lt;p&gt;멀티쓰레드라는 이름에서 알 수 있듯이 여러 쓰레드가 관련되며 각각이 가장 작은 실행 단위입니다. 쓰레드는 독립적이며 다른 쓰레드에게 영향을 미치지 않는 별도의 실행 경로를 가집니다.&lt;/p&gt;
&lt;p&gt;그러나 쓰레드가 동시에 동일한 리소스(락)에 액세스하려고 시도하는 경우 어떻게 될까요? 이것이 데드락이 발생하는 경우입니다. 실시간 금융 데이터 처리 시스템에서 협업하면서 이를 경험했습니다. 이 프로젝트에서는 외부 API에서 데이터를 가져 오고 복잡한 계산을 수행하며 공유 인메모리 데이터베이스를 업데이트하는 여러 쓰레드가 있었습니다.&lt;/p&gt;
&lt;p&gt;이 도구의 사용이 증가함에 따라 우리는 가끔씩 멈춤 현상이 발생하는 보고서를 받게 되었습니다. 쓰레드 덤프를 분석하면 일부 쓰레드가 락에 대한 원형 종속성을 형성하여 대기 상태에 갇혀 있는 것을 알 수 있었습니다.&lt;/p&gt;
&lt;p&gt;이 예에서는 두 개의 쓰레드(thread1 및 thread2)가 서로 다른 순서로 두 개의 락(lock1 및 lock2)을 획득하려고 시도합니다. 이는 원형 대기를 도입하여 데드락의 가능성을 높입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public class DeadlockExample {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -&amp;gt; {
            synchronized (lock1) {
                System.out.println(&amp;quot;Thread 1: Holding lock 1&amp;quot;);
                // Introducing a delay to increase the likelihood of deadlock
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println(&amp;quot;Thread 1: Holding lock 1 and lock 2&amp;quot;);
                }
            }
        });
        Thread thread2 = new Thread(() -&amp;gt; {
            synchronized (lock2) {
                System.out.println(&amp;quot;Thread 2: Holding lock 2&amp;quot;);
                // Introducing a delay to increase the likelihood of deadlock
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.println(&amp;quot;Thread 2: Holding lock 2 and lock 1&amp;quot;);
                }
            }
        });
        thread1.start();
        thread2.start();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 문제를 해결하기 위해 쓰레드가 항상 일관된 순서로 락을 획득하도록 코드를 리팩토링할 수 있습니다. 이를 위해 락의 전역 순서를 도입하고 모든 쓰레드가 동일한 순서를 따르도록 할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public class DeadlockSolution {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -&amp;gt; {
            synchronized (lock1) {
                System.out.println(&amp;quot;Thread 1: Holding lock 1&amp;quot;);
                // Introducing a delay to increase the likelihood of deadlock
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println(&amp;quot;Thread 1: Holding lock 2&amp;quot;);
                }
            }
        });
        Thread thread2 = new Thread(() -&amp;gt; {
            synchronized (lock1) {
                System.out.println(&amp;quot;Thread 2: Holding lock 1&amp;quot;);
                // Introducing a delay to increase the likelihood of deadlock
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println(&amp;quot;Thread 2: Holding lock 2&amp;quot;);
                }
            }
        });
        thread1.start();
        thread2.start();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Thread deadlocks를 방지하는 tips&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;락 순서 지정: 모든 쓰레드가 락을 획득할 때 동일한 순서를 따르도록하여 원형 대기를 방지합니다.&lt;/li&gt;
&lt;li&gt;락 타임아웃 구현: 쓰레드가 특정 시간 내에 락을 획득할 수 없는 경우, 모든 획득한 락을 해제하고 재시도합니다.&lt;/li&gt;
&lt;li&gt;중첩 락 회피: 다른 락이 이미 보유된 상태에서 중요한 섹션 내에서 락을 획득하는 것을 피합니다. 중첩 락은 데드락의 위험을 증가시킵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. Excessive garbage collection&lt;/h3&gt;
&lt;p&gt;자바의 가비지 컬렉션은 메모리를 관리해주는 주요한 기능입니다. 더 이상 필요하지 않은 객체를 자동으로 정리하여 개발자들의 삶을 훨씬 쉽게 만들어줍니다. 이 자동 가비지 컬렉션은 개발자들에게 편의를 제공하지만, 애플리케이션 성능에 영향을 미칠 수 있는 가비지 컬렉션에 할당된 CPU 사이클의 비용이 발생할 수 있습니다.&lt;/p&gt;
&lt;p&gt;전형적인 메모리 부족 오류 외에도, 가끔씩 애플리케이션이 멈추거나 느려지거나 애플리케이션 충돌이 발생할 수 있습니다. 또한 클라우드를 사용하는 경우 가비지 컬렉션 프로세스를 최적화하면 컴퓨팅 비용을 크게 절약할 수 있습니다. Uber라는 회사가 그러한 사례입니다. 이 회사는 고도로 효과적이고 낮은 위험, 대규모, 반자동화된 Go 가비지 컬렉션 튜닝 메커니즘을 사용하여 30개의 중요 서비스 전체에서 70,000개의 코어를 절약할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Excessive garbage collection을 방지하는 tips&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;로그 분석 및 튜닝: 완전한 가비지 컬렉션 주기나 긴 일시 정지 시간과 같은 패턴을 식별합니다.&lt;/li&gt;
&lt;li&gt;다양한 가비지 컬렉션 알고리즘을 평가하고 전환합니다. JDK 알고리즘인 Serial, Parallel, G1, Z GC 등을 고려합니다.&lt;/li&gt;
&lt;li&gt;애플리케이션의 작업 부하와 성능 특성을 기반으로 알고리즘을 선택합니다. 더 적합한 GC 알고리즘으로 전환하면 CPU 소비를 줄일 수 있습니다.&lt;/li&gt;
&lt;li&gt;과도한 객체 생성을 줄이기 위해 코드를 최적화합니다. HeapHero 또는 YourKit과 같은 메모리 프로파일링 도구를 사용하여 과도한 객체를 생성하는 부분을 식별합니다. 객체 풀링을 구현하여 객체를 재사용하고 할당 오버헤드를 줄입니다.&lt;/li&gt;
&lt;li&gt;가비지 컬렉션 중 CPU 소비에 영향을 미치도록 힙 크기를 수정합니다. 컬렉션 주기의 빈도를 줄이기 위해 힙 크기를 증가시키거나, 메모리 풋프린트가 낮은 애플리케이션의 경우 힙 크기를 감소시킵니다.&lt;/li&gt;
&lt;li&gt;클라우드에서 실행 중인 경우 작업 부하를 여러 인스턴스에 분산합니다. 리소스를 더 잘 활용하고 개별 인스턴스에 가중 부하를 줄이기 위해 컨테이너 인스턴스나 EC2 인스턴스의 수를 늘릴 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. Bloated Libraries and Dependencies&lt;/h3&gt;
&lt;p&gt;Maven과 Gradle과 같은 빌드 도구는 자바 프로젝트에서 종속성을 관리하는 방식을 혁신적으로 바꿔 놓았습니다. 이러한 도구들은 외부 라이브러리를 포함하는 간소화된 방법을 제공하고 프로젝트 구성 프로세스를 단순화합니다. 그러나 이러한 편의성에는 Bloated 된 라이브러리와 종속성의 위험이 따릅니다.&lt;/p&gt;
&lt;p&gt;실제로 2021년에 발표된 전체 연구에서는 애플리케이션의 컴파일된 코드에 포함된 종속성 중에 실제로 애플리케이션을 빌드하고 실행하는 데 필요하지 않은 것들이 있음을 밝혔습니다.&lt;/p&gt;
&lt;p&gt;소프트웨어 프로젝트는 버그 수정, 새로운 기능 및 새로운 종속성 등의 결과로 빠르게 성장하는 경향이 있습니다. 때로는 프로젝트가 비례치 않게 커져 개발자로서 효과적으로 유지하기 어려울 수 있습니다. 이로 인해 보안 취약점과 추가적인 성능 오버헤드도 발생할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이러한 상황에 처한 경우, 사용되지 않는 종속성 및 라이브러리를 제거하는 방법을 찾는 것이 좋습니다.&lt;/p&gt;
&lt;p&gt;자바 생태계 내에서는 종속성을 관리하기 위한 여러 도구들이 있습니다. 가장 일반적인 도구 중 몇 가지는 Maven 종속성 플러그인과 Gradle 종속성 분석 플러그인 등이 있습니다. 이 도구들은 사용되지 않는 종속성과 사용된 전이적 종속성(직접 선언하려는 것) 및 잘못된 구성(API vs implementation vs compileOnly 등)을 감지하는 데 꽤 효과적입니다.&lt;/p&gt;
&lt;p&gt;또한 Sonarqube와 JArchitect와 같은 다른 도구들도 활용할 수 있습니다. Intellij와 같은 일부 최신 IDE도 꽤 괜찮은 종속성 분석 기능을 제공합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bloated Libraries and Dependencies를 방지하는 tips&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;종속성 검사: 사용되지 않거나 오래된 라이브러리를 식별하기 위해 정기적인 검사를 수행하십시오. Maven Dependency Plugin이나 Gradle의 dependencyInsight와 같은 도구를 사용하여 종속성 분석을 지원할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;버전 관리: 종속성을 최신 상태로 유지하십시오. 버전 관리 시스템을 활용하여 종속성의 변경 사항을 추적하고 업데이트를 체계적으로 관리합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;종속성 범위: 종속성 범위(compile, runtime, test 등)를 효과적으로 활용하십시오. 최종 아티팩트의 크기를 줄이기 위해 컴파일 범위에 있는 종속성의 수를 최소화합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. Inefficient Code&lt;/h3&gt;
&lt;p&gt;비효율적인 코드&lt;/p&gt;
&lt;p&gt;어떤 개발자도 의도적으로 비효율적이거나 최적화되지 않은 코드를 작성하려 하지 않습니다. 그러나 최선의 의도에도 불구하고, 다양한 이유로 인해 비효율적인 코드가 제품에 반영될 수 있습니다. 이는 프로젝트의 시간 제약, 기술의 제한된 이해, 또는 개발자들이 최적화보다는 기능을 우선시해야 하는 변화하는 요구사항에서 비롯될 수 있습니다.&lt;/p&gt;
&lt;p&gt;비효율적인 예시&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String result = &amp;quot;&amp;quot;;
for (int i = 0; i &amp;lt; 1000; i++) {
   result += &amp;quot;example&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;개선된 예시&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;StringBuilder sb = new StringBuilder();
for (int i = 0; i &amp;lt; 1000; i++) {
   sb.append(&amp;quot;example&amp;quot;);
}
String result = sb.toString();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;비효율적인 코드는 증가된 메모리 사용, 더 긴 응답 시간, 전체 시스템 효율성 감소로 이어질 수 있습니다. 궁극적으로 비효율적인 코드는 사용자 경험을 저하시키고 운영 비용을 증가시키며 증가된 부하를 처리하기 위한 애플리케이션 확장을 제한할 수 있습니다.&lt;/p&gt;
&lt;p&gt;비효율적인 코드를 제거하는 것은 비효율성을 나타내는 패턴을 식별하는 것으로 시작합니다. 항상 주의를 기울여야 할 패턴 중 일부는 적절한 종료 조건이 없는 중첩된 루프, 불필요한 객체 생성과 인스턴스화, 과도한 동기화, 비효율적인 데이터베이스 쿼리 등이 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inefficient Code를 방지하는 tips&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;코드를 리팩토링하고 모듈화하여 불필요한 중복을 피합니다.&lt;/li&gt;
&lt;li&gt;I/O 작업 최적화: 주요 쓰레드를 차단하지 않도록 비동기 또는 병렬 I/O 작업을 사용합니다.&lt;/li&gt;
&lt;li&gt;특히 코드의 성능이 중요한 섹션에서 불필요한 객체 생성을 피합니다. 가능한 경우 객체를 재사용하고 객체 풀링 기법을 사용하는 것을 고려합니다.&lt;/li&gt;
&lt;li&gt;문자열을 빌드할 때 + 연산자로 문자열을 연결하는 대신 StringBuilder를 사용합니다. 이렇게 하면 불필요한 객체 생성을 피할 수 있습니다.&lt;/li&gt;
&lt;li&gt;효율적인 알고리즘과 데이터 구조를 사용합니다. 작업에 적합한 알고리즘과 데이터 구조를 선택하여 최적의 성능을 보장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6. Concurrency problems&lt;/h3&gt;
&lt;p&gt;쓰레드 동시성 문제는 여러 쓰레드가 공유 리소스에 동시에 접근할 때 발생하며, 종종 예상치 못한 동작으로 이어집니다.&lt;/p&gt;
&lt;p&gt;코드 작성에 오랜 시간을 보낸다면, 개발 주기 중에 나타나는 문제로 인한 좌절을 경험했을 것입니다. 이러한 문제를 효과적으로 식별하고 해결하는 것은 실제로 매우 어려운 일입니다.&lt;/p&gt;
&lt;p&gt;정확한 현실 성능을 파악하지 못하면, 이러한 문제들은 애플리케이션을 계속해서 괴롭힐 수 있습니다. 특히 복잡한 분산 시스템을 다룰 때 이러한 고통은 더욱 현실적입니다. 적절한 통찰력 없이는 정보화된 설계 결정을 내리거나 코드 변경의 영향을 평가하기가 어려울 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Concurrency problems를 방지하는 tips&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;원자 변수 사용: java.util.concurrent.atomic 패키지는 AtomicInteger 및 AtomicLong과 같은 클래스를 제공하여 명시적 동기화 없이도 원자적 작업을 가능하게 합니다.&lt;/li&gt;
&lt;li&gt;변경 가능한 객체 공유 피하기: 가능한 경우 클래스를 변경할 수 없도록 설계하여 동기화 필요성을 없애고 쓰레드 안전성을 보장합니다.&lt;/li&gt;
&lt;li&gt;Lock 경합 최소화: Lock 경합을 최소화하기 위해 미세한 잠금 또는 lock striping과 같은 기술을 사용하여 동일한 Lock에 대한 경쟁을 줄입니다.&lt;/li&gt;
&lt;li&gt;synchronized 키워드 활용: synchronized 블록이나 메서드를 생성하여 한 번에 하나의 쓰레드만 synchronized 코드 블록에 액세스할 수 있도록 합니다.&lt;/li&gt;
&lt;li&gt;쓰레드 안전한 데이터 구조 사용: Java의 java.util.concurrent 패키지는 ConcurrentHashMap, CopyOnWriteArrayList 및 BlockingQueue와 같은 쓰레드 안전한 데이터 구조를 제공하여 추가 동기화 없이도 동시 액세스를 처리할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>emotional developer/detect-Java</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742118</guid>
      <comments>https://sojw.tistory.com/1169742118#entry1169742118comment</comments>
      <pubDate>Sun, 7 Apr 2024 01:12:04 +0900</pubDate>
    </item>
    <item>
      <title>Clean Code: Optional Parameters</title>
      <link>https://sojw.tistory.com/1169742117</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@bubu.tripathy/clean-code-optional-parameters-327d67abbf90&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@bubu.tripathy/clean-code-optional-parameters-327d67abbf90&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;메서드에서&amp;nbsp;선택적&amp;nbsp;매개변수를&amp;nbsp;다룰&amp;nbsp;때는&amp;nbsp;긴&amp;nbsp;매개변수&amp;nbsp;목록이나&amp;nbsp;널&amp;nbsp;값&amp;nbsp;사용을&amp;nbsp;피하는&amp;nbsp;것이&amp;nbsp;좋습니다.&amp;nbsp;대신&amp;nbsp;메서드&amp;nbsp;오버로딩&amp;nbsp;또는&amp;nbsp;빌더&amp;nbsp;패턴으로&amp;nbsp;코드&amp;nbsp;가독성과&amp;nbsp;유지&amp;nbsp;관리성을&amp;nbsp;향상&amp;nbsp;시키는&amp;nbsp;것이&amp;nbsp;좋습니다.&amp;nbsp;이&amp;nbsp;방법들은&amp;nbsp;다양한&amp;nbsp;매개변수&amp;nbsp;집합을&amp;nbsp;가진&amp;nbsp;메서드를&amp;nbsp;호출할&amp;nbsp;때&amp;nbsp;더&amp;nbsp;깔끔한&amp;nbsp;인터페이스를&amp;nbsp;제공합니다.&lt;br /&gt;&lt;br /&gt;⭐️&amp;nbsp;메서드&amp;nbsp;오버로딩을&amp;nbsp;활용하여&amp;nbsp;서로&amp;nbsp;다른&amp;nbsp;매개변수&amp;nbsp;집합을&amp;nbsp;가진&amp;nbsp;메서드의&amp;nbsp;여러&amp;nbsp;버전을&amp;nbsp;생성하세요.&amp;nbsp;이렇게&amp;nbsp;하면&amp;nbsp;선택적&amp;nbsp;매개변수에&amp;nbsp;의존하지&amp;nbsp;않고도&amp;nbsp;명확하고&amp;nbsp;명시적으로&amp;nbsp;호출할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;⭐️&amp;nbsp;선택적&amp;nbsp;매개변수의&amp;nbsp;수가&amp;nbsp;상당히&amp;nbsp;많아지면&amp;nbsp;빌더&amp;nbsp;패턴을&amp;nbsp;구현하는&amp;nbsp;것을&amp;nbsp;고려하세요.&amp;nbsp;이&amp;nbsp;접근&amp;nbsp;방식은&amp;nbsp;별도의&amp;nbsp;빌더&amp;nbsp;클래스를&amp;nbsp;생성하여&amp;nbsp;선택적&amp;nbsp;매개변수가&amp;nbsp;있는&amp;nbsp;인스턴스를&amp;nbsp;구성하는&amp;nbsp;것입니다.&lt;br /&gt;&lt;br /&gt;⭐️&amp;nbsp;수많은&amp;nbsp;매개변수&amp;nbsp;대신&amp;nbsp;구성&amp;nbsp;개체를&amp;nbsp;사용하여&amp;nbsp;선택적&amp;nbsp;매개변수를&amp;nbsp;캡슐화할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이는&amp;nbsp;많은&amp;nbsp;수의&amp;nbsp;선택적&amp;nbsp;설정을&amp;nbsp;처리할&amp;nbsp;때&amp;nbsp;특히&amp;nbsp;유용할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;⭐️&amp;nbsp;메서드&amp;nbsp;오버로딩&amp;nbsp;또는&amp;nbsp;빌더&amp;nbsp;패턴을&amp;nbsp;구현할&amp;nbsp;때는&amp;nbsp;가능한&amp;nbsp;모든&amp;nbsp;매개변수&amp;nbsp;조합을&amp;nbsp;테스트해야&amp;nbsp;합니다.&amp;nbsp;이렇게&amp;nbsp;하면&amp;nbsp;메서드의&amp;nbsp;각&amp;nbsp;버전이&amp;nbsp;예상대로&amp;nbsp;작동하고&amp;nbsp;매개변수&amp;nbsp;간의&amp;nbsp;예기치&amp;nbsp;않은&amp;nbsp;상호&amp;nbsp;작용을&amp;nbsp;방지할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;어떤&amp;nbsp;접근&amp;nbsp;방식을&amp;nbsp;선택하든&amp;nbsp;명확성과&amp;nbsp;가독성을&amp;nbsp;우선시하세요.&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742117</guid>
      <comments>https://sojw.tistory.com/1169742117#entry1169742117comment</comments>
      <pubDate>Sun, 7 Apr 2024 00:44:31 +0900</pubDate>
    </item>
    <item>
      <title>What Is a Modular Monolith?</title>
      <link>https://sojw.tistory.com/1169742116</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@MilanJovanovicTech/what-is-a-modular-monolith-babd989a4ea2&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@MilanJovanovicTech/what-is-a-modular-monolith-babd989a4ea2&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;fdc7&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;What is a Modular Monolith?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈형&amp;nbsp;모놀리스는&amp;nbsp;애플리케이션을&amp;nbsp;잘&amp;nbsp;정의된&amp;nbsp;경계를&amp;nbsp;가진&amp;nbsp;독립적인&amp;nbsp;모듈&amp;nbsp;또는&amp;nbsp;구성&amp;nbsp;요소로&amp;nbsp;구조화하는&amp;nbsp;아키텍처&amp;nbsp;패턴입니다.&amp;nbsp;모듈은&amp;nbsp;논리적&amp;nbsp;경계를&amp;nbsp;기준으로&amp;nbsp;분할되어&amp;nbsp;관련&amp;nbsp;기능을&amp;nbsp;함께&amp;nbsp;그룹화합니다.&amp;nbsp;이&amp;nbsp;접근&amp;nbsp;방식은&amp;nbsp;시스템의&amp;nbsp;응집력을&amp;nbsp;크게&amp;nbsp;향상시킵니다.&lt;br /&gt;&lt;br /&gt;모듈은&amp;nbsp;느슨하게&amp;nbsp;결합되어&amp;nbsp;있어&amp;nbsp;모듈화와&amp;nbsp;분리를&amp;nbsp;더욱&amp;nbsp;촉진합니다.&amp;nbsp;모듈은&amp;nbsp;공용&amp;nbsp;API를&amp;nbsp;통해&amp;nbsp;통신하며,&amp;nbsp;이에&amp;nbsp;대한&amp;nbsp;자세한&amp;nbsp;내용은&amp;nbsp;모듈형&amp;nbsp;모놀리스&amp;nbsp;통신&amp;nbsp;패턴에&amp;nbsp;대한&amp;nbsp;글에서&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;그렇다면&amp;nbsp;모듈식&amp;nbsp;설계의&amp;nbsp;장점은&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;1400&quot; data-origin-height=&quot;742&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eROtMd/btsGpYOsfiL/8xDgAs7qfqa8X6Yseu4Qhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eROtMd/btsGpYOsfiL/8xDgAs7qfqa8X6Yseu4Qhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eROtMd/btsGpYOsfiL/8xDgAs7qfqa8X6Yseu4Qhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeROtMd%2FbtsGpYOsfiL%2F8xDgAs7qfqa8X6Yseu4Qhk%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;1400&quot; height=&quot;742&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;742&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;h1 id=&quot;62bb&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;Benefits of a Modular Monolith&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배포 간소화 - 복잡한 배포 전략이 필요한 마이크로서비스와 달리 모듈형 모놀리스는 단일 단위로 배포할 수 있습니다.&lt;/li&gt;
&lt;li&gt;성능 향상 - 모듈 간의 통신은 프로세스 중에 이루어집니다. 즉, 네트워크 지연 시간이나 데이터 직렬화/역직렬화 오버헤드가 없습니다.&lt;/li&gt;
&lt;li&gt;개발 속도 향상 - 관리할 코드베이스가 하나이므로 디버깅과 전반적인 개발 환경이 간소화됩니다.&lt;/li&gt;
&lt;li&gt;간편한 트랜잭션 관리 - 분산 시스템에서 트랜잭션 관리는 매우 까다롭습니다. 모듈형 모놀리스는 모듈이 동일한 데이터베이스를 공유할 수 있으므로 이 작업을 간소화합니다.&lt;/li&gt;
&lt;li&gt;운영 복잡성 감소 - 모듈형 모놀리스는 분산형 마이크로서비스 시스템을 관리하고 배포할 때 발생하는 운영 오버헤드를 줄여줍니다.&lt;/li&gt;
&lt;li&gt;마이크로서비스로의&amp;nbsp;손쉬운&amp;nbsp;전환&amp;nbsp;-&amp;nbsp;잘&amp;nbsp;구조화된&amp;nbsp;모듈식&amp;nbsp;모놀리스는&amp;nbsp;마이크로서비스&amp;nbsp;아키텍처로&amp;nbsp;가는&amp;nbsp;명확한&amp;nbsp;경로를&amp;nbsp;제공합니다.&amp;nbsp;필요에&amp;nbsp;따라&amp;nbsp;점진적으로&amp;nbsp;모듈을&amp;nbsp;별도의&amp;nbsp;서비스로&amp;nbsp;추출할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;af7b&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;Modular Monolith vs Microservices&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈형&amp;nbsp;모놀리스와&amp;nbsp;마이크로서비스의&amp;nbsp;가장&amp;nbsp;큰&amp;nbsp;차이점은&amp;nbsp;배포&amp;nbsp;방식에&amp;nbsp;있습니다.&amp;nbsp;마이크로서비스는&amp;nbsp;모듈형&amp;nbsp;모놀리스&amp;nbsp;내부의&amp;nbsp;논리적&amp;nbsp;경계를&amp;nbsp;물리적&amp;nbsp;경계로&amp;nbsp;확장합니다.&lt;br /&gt;&lt;br /&gt;마이크로서비스는&amp;nbsp;모듈화를&amp;nbsp;위한&amp;nbsp;명확한&amp;nbsp;전략을&amp;nbsp;제공하고&amp;nbsp;경계가&amp;nbsp;있는&amp;nbsp;컨텍스트를&amp;nbsp;분해합니다.&amp;nbsp;하지만&amp;nbsp;분산&amp;nbsp;시스템을&amp;nbsp;구축하지&amp;nbsp;않고도&amp;nbsp;이를&amp;nbsp;달성할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;문제는&amp;nbsp;사람들이&amp;nbsp;마이크로서비스를&amp;nbsp;사용하여&amp;nbsp;코드&amp;nbsp;경계를&amp;nbsp;강제한다는&amp;nbsp;것입니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7CtRj/btsGqNrP0El/O3yBB22QfbZLQKlzkzYX90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7CtRj/btsGqNrP0El/O3yBB22QfbZLQKlzkzYX90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7CtRj/btsGqNrP0El/O3yBB22QfbZLQKlzkzYX90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7CtRj%2FbtsGqNrP0El%2FO3yBB22QfbZLQKlzkzYX90%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;1400&quot; height=&quot;788&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신&amp;nbsp;모듈형&amp;nbsp;모놀리스를&amp;nbsp;구축하여&amp;nbsp;동일한&amp;nbsp;이점을&amp;nbsp;대부분&amp;nbsp;얻을&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;모듈형&amp;nbsp;모놀리스는&amp;nbsp;높은&amp;nbsp;응집력,&amp;nbsp;낮은&amp;nbsp;결합,&amp;nbsp;데이터&amp;nbsp;캡슐화,&amp;nbsp;비즈니스&amp;nbsp;기능에&amp;nbsp;대한&amp;nbsp;집중&amp;nbsp;등을&amp;nbsp;제공합니다.&lt;br /&gt;&lt;br /&gt;마이크로서비스는&amp;nbsp;이&amp;nbsp;모든&amp;nbsp;장점에&amp;nbsp;더해&amp;nbsp;독립적인&amp;nbsp;배포,&amp;nbsp;독립적인&amp;nbsp;확장성,&amp;nbsp;서비스별로&amp;nbsp;다양한&amp;nbsp;기술&amp;nbsp;스택을&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;기능을&amp;nbsp;제공합니다.&lt;br /&gt;&lt;br /&gt;모놀리식&amp;nbsp;코드베이스가&amp;nbsp;복잡해서&amp;nbsp;마이크로서비스를&amp;nbsp;선택하는&amp;nbsp;것이&amp;nbsp;아니라&amp;nbsp;이점을&amp;nbsp;위해&amp;nbsp;마이크로서비스를&amp;nbsp;선택하세요.&lt;br /&gt;&amp;mdash;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; href=&quot;https://twitter.com/simonbrown&quot;&gt;Simon Brown&lt;/a&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742116</guid>
      <comments>https://sojw.tistory.com/1169742116#entry1169742116comment</comments>
      <pubDate>Fri, 5 Apr 2024 23:49:29 +0900</pubDate>
    </item>
    <item>
      <title>mongodb bulk remove</title>
      <link>https://sojw.tistory.com/1169742115</link>
      <description>&lt;h3&gt;mongodb bulk remove&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/reference/method/Bulk.find.remove/&quot;&gt;https://www.mongodb.com/docs/manual/reference/method/Bulk.find.remove/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-data/mongodb/reference/mongodb/template-crud-operations.html&quot;&gt;https://docs.spring.io/spring-data/mongodb/reference/mongodb/template-crud-operations.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/community/forums/t/how-best-to-delete-a-huge-amount-of-data-from-a-collection/212849&quot;&gt;https://www.mongodb.com/community/forums/t/how-best-to-delete-a-huge-amount-of-data-from-a-collection/212849&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742115</guid>
      <comments>https://sojw.tistory.com/1169742115#entry1169742115comment</comments>
      <pubDate>Wed, 3 Apr 2024 21:32:13 +0900</pubDate>
    </item>
    <item>
      <title>Git Branch Model/Strategy</title>
      <link>https://sojw.tistory.com/1169742114</link>
      <description>&lt;div data-panel-type=&quot;info&quot;&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Release Train&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IT회사에서 일상적으로 사용하는 RT는 &quot;Release Train&quot;의 약자입니다. 소프트웨어 개발과정에서 사용 되는 용어로, 주로 Agile 또는 린소프트웨어 개발 방법론에서 활용됩니다. Release Train은 여러 팀이 협력하여 일정 주기마다 새로운 소프트웨어 버전을 배포하는 프로세스를 나타냅니다. 이 프로세스는 큰 프로젝트 또는 제품을 관리하고 지속적으로 배포하기 위해 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Release Train 접근 방식은 다음과 같이 동작합니다:&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; 일정한 주기(보통은 2주, 4주 등)로 소프트웨어 버전을 배포하는 시간 단위를 결정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;팀 협력:&lt;/b&gt; 여러 개발 팀이 하나의 Release Train에 참여합니다. 이 팀들은 동시에 개발을 진행하며, 주기마다 생성된 기능이나 개선사항을 공유하고 통합합니다.&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; 주기가 끝나면 통합 및 테스트를 마친 기능들을 하나의 큰 배포로써 출시합니다. 이것이 바로 Release Train이며, 사용자들에게 새로운 기능과 개선사항을 제공합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-panel-type=&quot;note&quot;&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;VS. Git Branch Strategy&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Git Flow , Github Flow&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;Git Flow는 흐름이 복잡하지만 branch를 체계적으로 관리할 수 있다. 따라서 긴 호흡으로 개발을 진행하며, 주기적으로 배포하고 QA, 배포 할 필요성이 있을 때 Git Flow를 추천한다.&lt;/li&gt;
&lt;li&gt;반대로 Github Flow는 작업 과정이 매우 단순하다는 장점이 있다. 따라서 Git을 처음 접하는 인원이 많거나 지속적으로 테스트하고 빠르게 배포되어야하는 서비스라면 Github Flow가 적합하다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Github Flow , Gitlab Flow&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;둘 다 master branch에서 시작하여 개발 중인 코드를 관리하고 기능 개발을 위해 새로운 branch를 생성하며 완료된 기능을 master branch로 병합하는 과정이 동일합니다. 또한 테스트와 리뷰를 거친 후 안정화된 코드를 production 환경에 배포하는 것 역시 동일.&lt;/li&gt;
&lt;li&gt;Gitlab flow가 Git flow와 Github flow의 특징을 결합한 방법론이라는 것입니다.&lt;/li&gt;
&lt;li&gt;Gitlab flow는 개발과 배포를 위한 유연성과 간단한 프로세스를 조합하여 팀이 더욱 효과적으로 협업하고 production 환경에 안정적인 코드를 배포할 수 있도록 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Github Flow&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBlaYY/btsDuxdSF8q/rdkn3KTDIMnVa8Gle7uKt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBlaYY/btsDuxdSF8q/rdkn3KTDIMnVa8Gle7uKt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBlaYY/btsDuxdSF8q/rdkn3KTDIMnVa8Gle7uKt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBlaYY%2FbtsDuxdSF8q%2Frdkn3KTDIMnVa8Gle7uKt0%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;899&quot; height=&quot;310&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ryAHZ/btsDrkl4M85/IDqitVMcjDt4vnLFgPNydk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ryAHZ/btsDrkl4M85/IDqitVMcjDt4vnLFgPNydk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ryAHZ/btsDrkl4M85/IDqitVMcjDt4vnLFgPNydk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FryAHZ%2FbtsDrkl4M85%2FIDqitVMcjDt4vnLFgPNydk%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;380&quot; height=&quot;467&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;571&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxrZ8I/btsDpbcwmRH/q70FUFiUeGfIJyz7Web5DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxrZ8I/btsDpbcwmRH/q70FUFiUeGfIJyz7Web5DK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxrZ8I/btsDpbcwmRH/q70FUFiUeGfIJyz7Web5DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxrZ8I%2FbtsDpbcwmRH%2Fq70FUFiUeGfIJyz7Web5DK%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;1280&quot; height=&quot;571&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;571&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Git Flow에 비해 굉장히 간단함, 처음 git을 접하는 사람에게 가장 간단하고 적응하기 쉬운 전략.&lt;/li&gt;
&lt;li&gt;master branch와 pull request 방식을 활용하여 굉장히 단순한 형태의 전략&lt;/li&gt;
&lt;li&gt;hotfix와 가장 작은 기능(feature), 배포(release)을 구분하지 않는다. 단지 우선순위가 어디가 높은가 라는 단계적 처리가 필요 하다.&lt;/li&gt;
&lt;li&gt;수시로 배포가 일어나고, CI/CD 파이프라인이 구성되어 있는 프로젝트에 유용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CI가 거의 필수적이며, 배포는 자동으로 진행할 수 있다.&lt;/li&gt;
&lt;li&gt;GitHub의 서비스 특성상 릴리즈 라는 개념이 없는 서비스를 진행하고 있어서 그런 것으로 보임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;release branch가 명확하지 않은 시스템에서 사용 하기 맞게 되어있다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Branch 정의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;master
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;product 배포 branch&lt;/li&gt;
&lt;li&gt;master branch는 어떤 때든 배포가 가능하다.&lt;/li&gt;
&lt;li&gt;master branch는 항상 최신의 상태이며, stable 상태로 Product에 배포되는 branch이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;새로운 feature branch
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 feature를 시작하기 위해 만드는 branch&lt;/li&gt;
&lt;li&gt;항상 master branch에서 분기&lt;/li&gt;
&lt;li&gt;Git Flow와는 다르게 feature, release, develop 등을 나누지 않음 &amp;rarr; commit 메시지를 명확하게 작성해야 함&lt;/li&gt;
&lt;li&gt;merge 준비가 완료되면 Pull Request를 통해 code review 단계를 진행&lt;/li&gt;
&lt;li&gt;Pull Request에서 code review가 완료 &amp;rarr; master branch로 반영&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;h3 data-ke-size=&quot;size23&quot;&gt;작업 과정 설명&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;master에서 새로운 branch 분기&lt;/li&gt;
&lt;li&gt;기능 개발 완료 시 master에 Pull Request 생성&lt;/li&gt;
&lt;li&gt;Pull Request에서 code review&lt;/li&gt;
&lt;li&gt;merge 시, product로 반영이 될 기능 이기에 이해관계가 연결된 사람들과 충분한 논의 이후 반영해야 한다 &amp;larr; 배포 관련 부분이 확정 되야 5번 단계로 넘어 가야 한다.&lt;/li&gt;
&lt;li&gt;review 및 test 완료 시 master branch로 merge&lt;/li&gt;
&lt;li&gt;master branch에서 즉시 배포진행 &amp;larr; 자동화 배포가 구성 되어 있어야 하지만, 수동으로 배포를 진행 해도 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Git Flow&lt;/h2&gt;
&lt;div data-expanded=&quot;true&quot; data-title=&quot;&quot; data-node-type=&quot;expand&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;978&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;1990&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tNcp5/btsDpxGGNt9/TGTS95ptI8sVEjEAKKcbX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tNcp5/btsDpxGGNt9/TGTS95ptI8sVEjEAKKcbX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tNcp5/btsDpxGGNt9/TGTS95ptI8sVEjEAKKcbX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtNcp5%2FbtsDpxGGNt9%2FTGTS95ptI8sVEjEAKKcbX1%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;1520&quot; height=&quot;1990&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;1990&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;647&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0Fdvg/btsDod9t5UV/lfUTa4kjmIkq1sMPjWCAMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0Fdvg/btsDod9t5UV/lfUTa4kjmIkq1sMPjWCAMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0Fdvg/btsDod9t5UV/lfUTa4kjmIkq1sMPjWCAMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0Fdvg%2FbtsDod9t5UV%2FlfUTa4kjmIkq1sMPjWCAMk%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;1280&quot; height=&quot;647&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;647&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1124&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;명확한 릴리즈 버전 관리를 위한 branch를 따로 관리하기 때문에 한 버전에 대한 유지보수가 용이함
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;운영 환경(master) 배포 branch와 개발 환경(develop) 배포 branch를 명시적으로 분리해서, 운영 환경에 어떤 코드 베이스가 배포 되어 있는지 한 눈에 확인할 수 있다는 점&lt;/li&gt;
&lt;li&gt;운영 환경에 언제 배포해도 상관없는 stable branch(master)를 별도로 관리해서, 장애 혹은 버그 수정이 필요한 경우 master branch를 기준으로 빠르게 수정 &amp;rarr; 아직 테스트가 완료되지 않은 feature branch가 운영 환경에 배포 되는걸 방지&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;기능 개발 단위 사이사이의 conflict를 최소화 할 수 있음&lt;/li&gt;
&lt;li&gt;명확한 배포 기간과 주기적인 버전이 정해진 프로젝트에 적합&lt;/li&gt;
&lt;li&gt;Git Flow 설계자 &lt;a href=&quot;https://nvie.com/about/&quot;&gt;Vincent Driessen&lt;/a&gt;의 &lt;a href=&quot;https://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;2020년 추가 의견&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-expanded=&quot;true&quot; data-title=&quot;&quot; data-node-type=&quot;expand&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;820&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모델은 지금으로부터 10년 전인 2010년에 고안된 것으로, Git 자체가 등장한 지 얼마 되지 않은 시점입니다. 이 글에서 설명하는 브랜칭 모델인 깃플로는 10년 동안 많은 소프트웨어 팀에서 큰 인기를 끌면서 사람들이 일종의 표준처럼 취급하기 시작했지만, 안타깝게도 도그마나 만병통치약처럼 여겨지기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 10년 동안 Git 자체는 전 세계를 강타 했으며, 적어도 제 필터 버블?에서는 Git으로 개발되는 가장 인기 있는 소프트웨어 유형이 웹 앱으로 더 많이 이동하고 있습니다. 웹 앱은 일반적으로 롤백 되지 않고 지속적으로 제공 되며, 여러 버전의 소프트웨어가 동시에 실행되도록 지원할 필요가 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10년 전 블로그 게시물을 작성할 때 염두에 두었던 소프트웨어의 종류가 아닙니다. 팀에서 소프트웨어의 지속적 배포를 수행하는 경우, 팀에 Git Flow를 무리하게 도입하는 대신 훨씬 더 간단한 워크 플로(예: GitHub 플로우)를 채택하는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 명시적으로 버전이 지정된 소프트웨어를 빌드 하거나 여러 버전의 소프트웨어를 지원해야 하는 경우에는 지난 10년 동안 사람들에게 그랬던 것처럼 Git Flow가 여전히 팀에 적합할 수 있습니다. 그렇다면 계속 읽어보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로, 만병통치약은 존재하지 않는다는 사실을 항상 기억하세요. 자신의 상황을 고려하세요. 미워하지 마세요. 스스로 결정하세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Branch 정의&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;master branch: 안정화된 버전의 코드(버전태그 추가), 제품으로 출시 될 수 있는 branch, 사용자에게 배포 가능한 상태만을 관리&lt;/li&gt;
&lt;li&gt;develop branch: 개발 중인 코드들의 base branch. 최신 개발 변경사항이 반영되어있는 branch(현재 개발중인 코드 반영)&lt;/li&gt;
&lt;li&gt;feature branch: 각 기능마다 develop을 기준으로 feature를 생성해서 개발을 진행.&lt;/li&gt;
&lt;li&gt;release branch: 이번 출시 버전을 준비하는 branch, QA 진행 및 배포 준비 역할, 해당 release가 종료 되면 삭제 가능&lt;/li&gt;
&lt;li&gt;hotfix branch: 출시 버전에서 발생한 버그를 수정하는 branch. master Branch에서 버그 발생하면 바로 hotfix Branch를 분기해서 수정, 배포한 후 관리하는 branch&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;작업 과정 설명&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;master에서 develop을 분기&lt;/li&gt;
&lt;li&gt;개발자들은 develop branch에 자유롭게 커밋&lt;/li&gt;
&lt;li&gt;기능 구현이 있는 경우 develop에서 feature-* branch를 분기&lt;/li&gt;
&lt;li&gt;배포를 준비하기 위해 develop에서 release-* branch를 분기&lt;/li&gt;
&lt;li&gt;테스트를 진행하면서 발생하는 버그 수정은 release-* branch에 직접 수정 및 반영&lt;/li&gt;
&lt;li&gt;테스트 완료 및 배포 준비를 완료하면 release -&amp;gt; main으로 merge하고, release -&amp;gt; develop으로 develop에도 동일하게 반영한다.&lt;/li&gt;
&lt;li&gt;배포 이후에 bug가 있을 경우 hotfix branch를 사용하여 해결한다. 그리고 hotfix -&amp;gt; master, hotfix -&amp;gt; develop으로 해당 commit을 반영한다.&lt;/li&gt;
&lt;li&gt;배포를 버전별로 관리하기 위해 master에 tag를 붙인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Gitlab Flow&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2023년 추가 된 concept: &lt;a href=&quot;https://about.gitlab.com/blog/2023/07/27/gitlab-flow-duo/&quot;&gt;https://about.gitlab.com/blog/2023/07/27/gitlab-flow-duo/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-expanded=&quot;true&quot; data-title=&quot;&quot; data-node-type=&quot;expand&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;834&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C6wBg/btsDogLPyyU/ecMsDxQnevZHdNpAYzkdVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C6wBg/btsDogLPyyU/ecMsDxQnevZHdNpAYzkdVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C6wBg/btsDogLPyyU/ecMsDxQnevZHdNpAYzkdVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC6wBg%2FbtsDogLPyyU%2FecMsDxQnevZHdNpAYzkdVK%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;590&quot; height=&quot;766&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blmsOc/btsDrlkVifY/PccUWxkqpxbUAka0KoUWl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blmsOc/btsDrlkVifY/PccUWxkqpxbUAka0KoUWl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blmsOc/btsDrlkVifY/PccUWxkqpxbUAka0KoUWl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblmsOc%2FbtsDrlkVifY%2FPccUWxkqpxbUAka0KoUWl1%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;1280&quot; height=&quot;541&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;541&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1078&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Git Flow &amp;harr;︎ Github Flow의 절충안&lt;/li&gt;
&lt;li&gt;Production branch가 존재(Git Flow의 master branch 역할과 같음)&lt;/li&gt;
&lt;li&gt;Gitlab Flow의 master branch는 production branch로 merge됨&lt;/li&gt;
&lt;li&gt;pre-production branch는 production branch로 넘어가기 전에 QA/Test를 진행하는 branch&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;Branch 정의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;master&lt;/li&gt;
&lt;li&gt;pre-prodution
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;production으로 넘어가기 전의 branch&lt;/li&gt;
&lt;li&gt;QA/Test 등 배포 준비 작업을 담당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;production
&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;새로운 feature branch
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;github flow의 새로운 feature branch처럼 사용&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;h3 data-ke-size=&quot;size23&quot;&gt;과정 설명&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;master에서 새로운 branch 분기&lt;/li&gt;
&lt;li&gt;기능 개발 완료 시 master에 Pull Request 생성&lt;/li&gt;
&lt;li&gt;Pull Request에서 code review&lt;/li&gt;
&lt;li&gt;다음 배포 버전의 Pre-production branch 생성 후, QA/Test 진행&lt;/li&gt;
&lt;li&gt;Production branch 생성 및 배포&lt;/li&gt;
&lt;li&gt;(Github Flow에서 배포만을 위해 추가된 Production branch와 테스트를 위한 Pre-production branch 빼고 동일합니다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Trunk-Based Development&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://paulhammant.com/2013/04/05/what-is-trunk-based-development/&quot;&gt;https://paulhammant.com/2013/04/05/what-is-trunk-based-development/&lt;/a&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&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;단일 branch를 사용하여 개발을 진행하며 모든 개발자가 동일한 branch(trunk)에서 작업.&lt;/li&gt;
&lt;li&gt;개발자는 자신이 작업한 변경사항을 주기적으로 commit하고 다른 개발자의 변경사항과 통합합니다. 이로써 지속적인 통합과 릴리즈를 강조하며 branch 관리에 따른 복잡성을 줄 이는 장점.&lt;/li&gt;
&lt;li&gt;그러나 branch 충돌이 발생할 수 있고 변경 사항이 모든 개발자에게 바로 적용되기 때문에 신중하게 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Branch 정의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;trunk(=master): 하나의 branch에서 모든 개발자가 작업을 합니다. 실제 개발과 배포를 위한 branch를 하나로 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-expanded=&quot;true&quot; data-title=&quot;&quot; data-node-type=&quot;expand&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1040&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고(Updating,,)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://techblog.woowahan.com/2553/&quot;&gt;https://techblog.woowahan.com/2553/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>emotional developer</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742114</guid>
      <comments>https://sojw.tistory.com/1169742114#entry1169742114comment</comments>
      <pubDate>Sun, 14 Jan 2024 21:10:42 +0900</pubDate>
    </item>
    <item>
      <title>Brian Chesky&amp;rsquo;s new playbook : co-founder and CEO of Airbnb</title>
      <link>https://sojw.tistory.com/1169742113</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=4ef0juAMqoE&amp;amp;t=1s&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=4ef0juAMqoE&amp;amp;t=1s&lt;/a&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;브라이언&amp;nbsp;체스키는&amp;nbsp;에어비앤비의&amp;nbsp;공동창업자이자&amp;nbsp;CEO입니다.&amp;nbsp;브라이언의&amp;nbsp;리더십&amp;nbsp;아래&amp;nbsp;에어비앤비는&amp;nbsp;220여&amp;nbsp;개&amp;nbsp;국가와&amp;nbsp;지역에서&amp;nbsp;15억&amp;nbsp;명&amp;nbsp;이상의&amp;nbsp;게스트를&amp;nbsp;맞이한&amp;nbsp;400만&amp;nbsp;명&amp;nbsp;이상의&amp;nbsp;호스트가&amp;nbsp;참여하는&amp;nbsp;커뮤니티로&amp;nbsp;성장했습니다.&amp;nbsp;저는&amp;nbsp;브라이언의&amp;nbsp;리더십&amp;nbsp;아래에서&amp;nbsp;일할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;특권을&amp;nbsp;누렸기&amp;nbsp;때문에&amp;nbsp;방송에&amp;nbsp;브라이언을&amp;nbsp;모시게&amp;nbsp;되어&amp;nbsp;큰&amp;nbsp;영광입니다.&amp;nbsp;이야기를&amp;nbsp;나눠보겠습니다:&lt;br /&gt;-&amp;nbsp;에어비앤비가&amp;nbsp;상품&amp;nbsp;관리에&amp;nbsp;대한&amp;nbsp;생각을&amp;nbsp;바꾼&amp;nbsp;방법&lt;br /&gt;-&amp;nbsp;기업에서&amp;nbsp;관료주의가&amp;nbsp;발생하는&amp;nbsp;이유와&amp;nbsp;이를&amp;nbsp;방지하는&amp;nbsp;방법&lt;br /&gt;-&amp;nbsp;창업자가&amp;nbsp;디테일에&amp;nbsp;집중하는&amp;nbsp;것의&amp;nbsp;중요성&lt;br /&gt;-&amp;nbsp;에어비앤비가&amp;nbsp;전통적인&amp;nbsp;성장&amp;nbsp;채널에서&amp;nbsp;벗어난&amp;nbsp;이유와&amp;nbsp;그&amp;nbsp;대신에&amp;nbsp;하고&amp;nbsp;있는&amp;nbsp;일&lt;br /&gt;-&amp;nbsp;에어비앤비가&amp;nbsp;새로&amp;nbsp;출시한&amp;nbsp;기능&lt;br /&gt;-&amp;nbsp;브라이언이&amp;nbsp;팀원들에게&amp;nbsp;야심찬&amp;nbsp;목표를&amp;nbsp;세우도록&amp;nbsp;독려하는&amp;nbsp;방법과&amp;nbsp;이유&lt;br /&gt;-&amp;nbsp;아직&amp;nbsp;증명해야&amp;nbsp;할&amp;nbsp;것이&amp;nbsp;많다고&amp;nbsp;말하는&amp;nbsp;이유&lt;/blockquote&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://www.linkedin.com/search/results/content/?keywords=%EC%9D%98%EC%82%AC%20%EA%B2%B0%EC%A0%95%20%EA%B3%BC%EC%A0%95%EC%9D%84%20%EC%9C%84%EC%9E%84%ED%96%88%EB%8D%94%EB%8B%88%2C%20%EC%86%8D%EB%8F%84%EA%B0%80%20%EB%8D%94%20%EB%8A%90%EB%A0%A4%EC%A1%8C%EC%8A%B5%EB%8B%88%EB%8B%A4.&amp;amp;sid=YVe&amp;amp;update=urn%3Ali%3Afs_updateV2%3A(urn%3Ali%3Aactivity%3A7139212930121682944%2CBLENDED_SEARCH_FEED%2CEMPTY%2CDEFAULT%2Cfalse)&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.linkedin.com/search/results/content/?keywords=%EC%9D%98%EC%82%AC%20%EA%B2%B0%EC%A0%95%20%EA%B3%BC%EC%A0%95%EC%9D%84%20%EC%9C%84%EC%9E%84%ED%96%88%EB%8D%94%EB%8B%88%2C%20%EC%86%8D%EB%8F%84%EA%B0%80%20%EB%8D%94%20%EB%8A%90%EB%A0%A4%EC%A1%8C%EC%8A%B5%EB%8B%88%EB%8B%A4.&amp;amp;sid=YVe&amp;amp;update=urn%3Ali%3Afs_updateV2%3A(urn%3Ali%3Aactivity%3A7139212930121682944%2CBLENDED_SEARCH_FEED%2CEMPTY%2CDEFAULT%2Cfalse)&lt;/a&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;[에어비앤비가 겪었던 문제]&lt;br /&gt;- 조직이 커지면서, 팀들은 각 팀에게 오너십을 달라고 요청했다.&lt;br /&gt;- 각 팀에게 의사결정권을 위임했더니, 오히려 프로덕트 런칭 속도가 느려졌다. 방향성을 결정하는 데 혼란이 있었기 때문이다.&lt;br /&gt;- 이 영향으로 2015년부터 2020년까지 에어비앤비 프로덕트가 크게 바뀌지 못했다.&lt;br /&gt;&lt;br /&gt;[문제를 겪으면서 갖게된 생각]&lt;br /&gt;- 팀원들은 명확한 방향성을 원한다. CEO가 리더십을 가지고 프로덕트를 이끌어야 한다. 모두가 같은 방향을 바라볼 수 있도록 만드는 것이 가장 중요하다.&lt;br /&gt;- 매니저의 가장 중요한 역할은 자신의 분야에서 중요한 결정을 내리는 것이다. 사람들을 관리하는 건 두번째로 중요한 역할이다. 실무를 못하면서 조직 구성원을 제대로 관리하는 건 불가능하다.&lt;br /&gt;- 데이터를 보는 것이 중요하지만, 이해하지 못하는 데이터는 시체다. 결과를 이해하지 못하는 AB 테스트는 잘못된 방향으로 이끌 수 있다.&lt;br /&gt;- 엔지니어와 마케터의 관계가 가까워야 한다. 엔지니어는 쉐프이고, 마케터는 웨이터다. 둘이 친하지 않으면 손님에게 최고의 경험을 줄 수 없다.&lt;br /&gt;&lt;br /&gt;[변화]&lt;br /&gt;- 관리자 직급을 크게 줄였다 (현재 직원은 7,000명, 기업가치는 100조)&lt;br /&gt;- 진행하는 프로젝트를 크게 줄였다.&lt;br /&gt;- 수천개의 AB 테스트 대신, 1년에 두번 크게 런칭 하는 것에 집중한다.&lt;br /&gt;- CEO는 런칭의 모든 디테일에 참여한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>ing.</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742113</guid>
      <comments>https://sojw.tistory.com/1169742113#entry1169742113comment</comments>
      <pubDate>Sun, 10 Dec 2023 23:11:50 +0900</pubDate>
    </item>
    <item>
      <title>TDD Isn't Design</title>
      <link>https://sojw.tistory.com/1169742112</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tidyfirst.substack.com/p/tdd-isnt-design?fbclid=IwAR2CvJPKgRkoSiKl6LfHIugUsFyJI2bFkfrB80oebLdb_V4PeWbJgaWBUBw&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tidyfirst.substack.com/p/tdd-isnt-design?fbclid=IwAR2CvJPKgRkoSiKl6LfHIugUsFyJI2bFkfrB80oebLdb_V4PeWbJgaWBUBw&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프롬프트는 다음과 같았습니다: &quot;TDD만으로 훌륭한 시스템 설계가 나올 수 있다는 생각은 마음에 들지 않습니다.&quot;&lt;br /&gt;결론적으로 동의합니다. 당신은&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #292c32; text-align: start;&quot;&gt;디자인 결정을 내려야 합니다.&lt;/span&gt;&amp;nbsp;더 자세한 답변은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금이라도 상식이 있는 사람이라면 TDD가 디자인의 필요성을 대체한다고 말하지 않습니다. 핵심 질문은 '언제'입니다. &lt;span style=&quot;background-color: #ffffff; color: #292c32; text-align: start;&quot;&gt;첫 번째 테스트를 작성하고 통과하기 전에 몇 가지 구현 디자인 결정을 제안하고 있습니다.&lt;/span&gt;&amp;nbsp;특히 몇 달에서 몇 년이 걸리던 과거의 디자인 '단계'와 비교하면 그렇게 끔찍해 보이지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #404040; text-align: start;&quot;&gt;TDD offers:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터페이스 디자인 결정에 대한 즉각적인 피드백. 여전히 결정을 내려야 합니다. 결정한 만큼 디자인이 좋아지지만, 결정의 질에 따라 고통도 반비례하게 됩니다.&lt;/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;span style=&quot;background-color: #ffffff; color: #292c32; text-align: start;&quot;&gt;인터페이스 디자인 결정이 있는 상황에서 구현 디자인 결정을 내리는 데 자신이 없다면 괜찮습니다. 구현 디자인 결정을 몇 개만 내려야 하는지 실험해 보세요. 저는 최소한의 결정이 무엇인지 궁금합니다.&lt;/span&gt; 경험상&amp;nbsp;답은&amp;nbsp;'0'인&amp;nbsp;것으로&amp;nbsp;나타났습니다.&amp;nbsp;이&amp;nbsp;숫자는&amp;nbsp;직접&amp;nbsp;확인해&amp;nbsp;보시기&amp;nbsp;바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742112</guid>
      <comments>https://sojw.tistory.com/1169742112#entry1169742112comment</comments>
      <pubDate>Fri, 8 Dec 2023 16:00:51 +0900</pubDate>
    </item>
    <item>
      <title>Speeding Up Spring Boot/JUnit tests</title>
      <link>https://sojw.tistory.com/1169742111</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.ankushchoubey.com/spring-boot-junit-faster/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.ankushchoubey.com/spring-boot-junit-faster/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;use-right-test-slice-saved-25-running-time&quot; style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;&lt;b&gt;Use Right Test Slice&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Saved 25% running time)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 &lt;span style=&quot;background-color: #ffffff; color: #515151; text-align: start;&quot;&gt;runner가&lt;/span&gt;&amp;nbsp;Spring Boot와 함께 제공됩니다.&lt;br /&gt;&lt;br /&gt;SpringBootTest가 가장 일반적입니다. 주로 @DirtiesContent와 함께 사용되는데, 기본적으로 모든 테스트 클래스 후에 Springboot을 다시 시작하므로 이상적이지 않습니다.&lt;br /&gt;&lt;br /&gt;스프링부트테스트는 통합 테스트에 사용됩니다. 모든 테스트가 이를 사용하는 것은 바람직하지 않습니다.&lt;br /&gt;가능한 한 최소한의 스프링 부팅 인프라를 로드하면서도 정확한 테스트를 보장하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;span style=&quot;background-color: #ffffff; color: #292c32; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;테스트가 DB와 관련된 경우. 데이터몽고테스트 또는 @Import 어노테이션이 있는 동등한 JPA &lt;span style=&quot;background-color: #ffffff; color: #515151; text-align: start;&quot;&gt;runner&lt;/span&gt;를 사용합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;테스트가 웹/컨트롤러와 관련된 경우. WebFluxTest 또는 이와 동등한 Spring MVC 런너를 사용합니다. 임베디드 MongoDB를 함께 사용하려면 @AutoConfigureDataMongo를 사용하세요. 대부분의 다른 시스템에도 @AutoConfigure{systemName}으로 시작하는 어노테이션이 있습니다.&lt;/li&gt;
&lt;li&gt;중요: 테스트에서 단일 빈을 초기화해야 하는 경우. @import와 함께 @ExtendWith(SpringRunner.class)를 사용하여 초기화할 빈을 지정하세요.&lt;/li&gt;
&lt;li&gt;가장 좋은 경우: 순전히 자바 기반이며 스프링 부팅을 포함하지 않는 테스트를 목표로 하되, 모든 시나리오에서 가능한 것은 아닙니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;speeding-up-springboottest-and-avoiding-dirtiescontext-saved-25-running-time&quot; style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;&lt;b&gt;Speeding up @SpringBootTest and avoiding @DirtiesContext&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Saved 25% running time)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DirtiesContext는&amp;nbsp;각&amp;nbsp;테스트&amp;nbsp;또는&amp;nbsp;각&amp;nbsp;테스트&amp;nbsp;클래스&amp;nbsp;후에&amp;nbsp;Spring&amp;nbsp;컨텍스트를&amp;nbsp;다시&amp;nbsp;생성하는&amp;nbsp;어노테이션입니다.&amp;nbsp;DirtiesContext를&amp;nbsp;사용하지&amp;nbsp;않으려면&amp;nbsp;모든&amp;nbsp;테스트가&amp;nbsp;동일한&amp;nbsp;데이터에&amp;nbsp;의존하지&amp;nbsp;않도록&amp;nbsp;하세요.&amp;nbsp;이를&amp;nbsp;위해&amp;nbsp;테스트&amp;nbsp;데이터&amp;nbsp;팩토리에서&amp;nbsp;데이터&amp;nbsp;생성을&amp;nbsp;래핑하고&amp;nbsp;생성된&amp;nbsp;데이터가&amp;nbsp;무작위인지&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;앞서&amp;nbsp;언급했듯이&amp;nbsp;@SpringBootTest를&amp;nbsp;사용하지&amp;nbsp;않는&amp;nbsp;것이&amp;nbsp;좋지만,&amp;nbsp;어쩔&amp;nbsp;수&amp;nbsp;없이&amp;nbsp;사용해야&amp;nbsp;하는&amp;nbsp;경우&amp;nbsp;@DirtiesContext&amp;nbsp;없이&amp;nbsp;WebEnvironment.MOCK을&amp;nbsp;사용해야&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #eeeeff; color: #515151; text-align: start;&quot;&gt;@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;빈&amp;nbsp;생성을&amp;nbsp;제한하려면&amp;nbsp;@Import&amp;nbsp;또는&amp;nbsp;@ContextConfiguration과&amp;nbsp;함께&amp;nbsp;사용하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;run-tests-in-parallel-saved-37-running-time&quot; style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;&lt;b&gt;Run tests in parallel&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Saved 37% running time)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #eeeeff; color: #515151; text-align: start;&quot;&gt;test/resource/junit-platform.properties&lt;/span&gt;에 &lt;span style=&quot;background-color: #eeeeff; color: #515151; text-align: start;&quot;&gt;junit-platform.properties&lt;/span&gt; 파일을 생성하고 다음 최소값을 추가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #eeeeff; color: #515151; text-align: start;&quot;&gt;junit.jupiter.execution.parallel.enabled = true&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;병렬로 실행하려는 모든 클래스에 다음을 추가합니다. &lt;span style=&quot;background-color: #eeeeff; color: #515151; text-align: left;&quot;&gt;@Execution(CONCURRENT)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;junit-platform.properties에&amp;nbsp;추가하기&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;aspectj&quot; style=&quot;background-color: #323443; color: #f8f8f2; text-align: start;&quot;&gt;&lt;code&gt;junit.jupiter.execution.parallel.mode.default = same_thread|concurrent
junit.jupiter.execution.parallel.mode.classes.default =  same_thread|concurrent&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;232&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QdyQ0/btsAXftsTp2/PyJ9IAA6chRVPy7EQyUg31/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QdyQ0/btsAXftsTp2/PyJ9IAA6chRVPy7EQyUg31/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QdyQ0/btsAXftsTp2/PyJ9IAA6chRVPy7EQyUg31/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQdyQ0%2FbtsAXftsTp2%2FPyJ9IAA6chRVPy7EQyUg31%2Ftfile.svg&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;232&quot; height=&quot;150&quot; data-origin-width=&quot;232&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부 테스트는 병렬로 실행할 수 없으므로 &lt;span style=&quot;background-color: #eeeeff; color: #515151; text-align: start;&quot;&gt;@Execution(CONCURRENT)&lt;/span&gt;를 수동으로 추가하는 것을 선호합니다.&lt;br /&gt;다른 데이터에 대해 &lt;span style=&quot;background-color: #ffffff; color: #515151; text-align: start;&quot;&gt;asserting&lt;/span&gt;하여 @DataMongoTest로 데이터 테스트를 찾았습니다.&lt;br /&gt;&lt;span style=&quot;background-color: #eeeeff; color: #515151; text-align: start;&quot;&gt;@Execution(CONCURRENT)&lt;/span&gt;의 또 다른 긍정적인 효과는 이러한 테스트가 먼저 실행된다는 것입니다. 그리고 이러한 테스트는 &lt;span style=&quot;background-color: #ffffff; color: #515151; text-align: start;&quot;&gt;SAME_THREAD mode&lt;/span&gt;보다 빠르기 때문에 즉각적인 피드백으로 이어집니다.&lt;/p&gt;</description>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742111</guid>
      <comments>https://sojw.tistory.com/1169742111#entry1169742111comment</comments>
      <pubDate>Sun, 26 Nov 2023 23:44:10 +0900</pubDate>
    </item>
    <item>
      <title>Optimizing Spring Integration Tests</title>
      <link>https://sojw.tistory.com/1169742110</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.baeldung.com/spring-tests&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.baeldung.com/spring-tests&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;intro&quot; data-ke-size=&quot;size16&quot;&gt;주요 부분이라고 생각한 것만 한글화.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;intro&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;bd-intro&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;intro&quot; data-ke-size=&quot;size26&quot;&gt;2. Integration Tests&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통합 테스트는 자동화된 테스트 suites의 기본적인 부분입니다. 하지만 건강한 테스트 피라미드를 따른다면 단위 테스트만큼 많지는 않아야 합니다. Spring과 같은 프레임워크에 의존하면 시스템의 특정 동작에 대한 위험을 제거하기 위해 상당한 양의 통합 테스트가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring 모듈(데이터, 보안, 소셜 등)을 사용하여 코드를 더 단순화할수록 통합 테스트의 필요성은 더 커집니다. 특히 인프라의 일부분을 @Configuration 클래스로 옮길 때 더욱 그렇습니다.&lt;br /&gt;&lt;br /&gt;&quot;프레임워크를&amp;nbsp;테스트&quot;해서는&amp;nbsp;안&amp;nbsp;되지만,&amp;nbsp;프레임워크가&amp;nbsp;우리의&amp;nbsp;요구&amp;nbsp;사항을&amp;nbsp;충족하도록&amp;nbsp;구성되어&amp;nbsp;있는지&amp;nbsp;확실히&amp;nbsp;확인해야&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;통합&amp;nbsp;테스트는&amp;nbsp;신뢰를&amp;nbsp;구축하는&amp;nbsp;데&amp;nbsp;도움이&amp;nbsp;되지만&amp;nbsp;대가가&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;실행 속도가 느려지므로 빌드 속도가 느려집니다.&lt;/li&gt;
&lt;li&gt;또한 통합 테스트는 더 넓은 테스트 범위를 의미하므로 대부분의 경우 이상적이지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;bd-web-apps&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;web-apps&quot; data-ke-size=&quot;size26&quot;&gt;3. Testing Web Apps&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에는 웹 애플리케이션을 테스트하기 위한 몇 가지 옵션이 있으며, 대부분의 Spring 개발자는 이러한 옵션에 익숙합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #292c32; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;MockMvc: 비반응형 웹 앱에 유용한 서블릿 API를 모의 처리 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;TestRestTemplate: 특정 앱을 가리키는 데 사용할 수 있으며, 모의 서블릿이 바람직하지 않은 비반응형 웹 앱에 유용합니다.&lt;/li&gt;
&lt;li&gt;웹테스트클라이언트: 모의 요청/응답을 사용하거나 실제 서버를 호출하는 반응형 웹 앱용 테스트 도구입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미&amp;nbsp;이러한&amp;nbsp;주제를&amp;nbsp;다루는&amp;nbsp;기사가&amp;nbsp;있으므로&amp;nbsp;이에&amp;nbsp;대해서는&amp;nbsp;따로&amp;nbsp;설명하지&amp;nbsp;않겠습니다.&lt;br /&gt;더 자세히 알아보고 싶으시다면 언제든지 찾아보시기 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;bd-optimising&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;optimising&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. Optimizing Execution Time&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통합&amp;nbsp;테스트는&amp;nbsp;훌륭합니다.&amp;nbsp;통합&amp;nbsp;테스트는&amp;nbsp;우리에게&amp;nbsp;상당한&amp;nbsp;자신감을&amp;nbsp;줍니다.&amp;nbsp;또한&amp;nbsp;적절하게&amp;nbsp;구현하면&amp;nbsp;앱의&amp;nbsp;의도를&amp;nbsp;매우&amp;nbsp;명확하게&amp;nbsp;설명할&amp;nbsp;수&amp;nbsp;있으며,&amp;nbsp;모의&amp;nbsp;테스트와&amp;nbsp;설정&amp;nbsp;노이즈가&amp;nbsp;줄어듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만&amp;nbsp;앱이&amp;nbsp;성숙해지고&amp;nbsp;개발이&amp;nbsp;쌓이면&amp;nbsp;빌드&amp;nbsp;시간은&amp;nbsp;필연적으로&amp;nbsp;늘어납니다.&amp;nbsp;빌드&amp;nbsp;시간이&amp;nbsp;길어지면&amp;nbsp;매번&amp;nbsp;모든&amp;nbsp;테스트를&amp;nbsp;계속&amp;nbsp;실행하는&amp;nbsp;것이&amp;nbsp;비현실적으로&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;그&amp;nbsp;후에는&amp;nbsp;피드백&amp;nbsp;루프에&amp;nbsp;영향을&amp;nbsp;미치고&amp;nbsp;모범&amp;nbsp;개발&amp;nbsp;사례를&amp;nbsp;따르는&amp;nbsp;데&amp;nbsp;방해가&amp;nbsp;됩니다.&lt;br /&gt;&lt;br /&gt;또한&amp;nbsp;통합&amp;nbsp;테스트는&amp;nbsp;본질적으로&amp;nbsp;비용이&amp;nbsp;많이&amp;nbsp;듭니다.&amp;nbsp;일종의&amp;nbsp;지속성을&amp;nbsp;시작하거나,&amp;nbsp;요청을&amp;nbsp;전송하거나(로컬호스트를&amp;nbsp;벗어나지&amp;nbsp;않더라도),&amp;nbsp;일부&amp;nbsp;IO를&amp;nbsp;수행하는&amp;nbsp;데는&amp;nbsp;시간이&amp;nbsp;걸립니다.&lt;br /&gt;&lt;br /&gt;테스트&amp;nbsp;실행을&amp;nbsp;포함하여&amp;nbsp;빌드&amp;nbsp;시간을&amp;nbsp;주시하는&amp;nbsp;것이&amp;nbsp;가장&amp;nbsp;중요합니다.&amp;nbsp;그리고&amp;nbsp;이&amp;nbsp;시간을&amp;nbsp;줄이기&amp;nbsp;위해&amp;nbsp;Spring에서&amp;nbsp;적용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;트릭이&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;다음&amp;nbsp;섹션에서는&amp;nbsp;빌드&amp;nbsp;시간을&amp;nbsp;최적화하는&amp;nbsp;데&amp;nbsp;도움이&amp;nbsp;되는&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;사항과&amp;nbsp;속도에&amp;nbsp;영향을&amp;nbsp;줄&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;함정에&amp;nbsp;대해&amp;nbsp;알아보겠습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;현명한 프로필 사용 - 프로필이 성능에 미치는 영향&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MockBean 재검토 - 모킹이 성능에 미치는 영향&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MockBean 리팩토링 - 성능 향상을 위한 대안&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DirtiesContext에 대해 신중하게 생각하기 - 유용하지만 위험한 주석과 이를 사용하지 않는 방법&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;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 id=&quot;bd-1-using-profiles-wisely&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;1-using-profiles-wisely&quot; data-ke-size=&quot;size23&quot;&gt;4.1. Using Profiles Wisely&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로필은&amp;nbsp;매우&amp;nbsp;깔끔한&amp;nbsp;도구입니다.&amp;nbsp;즉,&amp;nbsp;앱의&amp;nbsp;특정&amp;nbsp;영역을&amp;nbsp;활성화&amp;nbsp;또는&amp;nbsp;비활성화할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;간단한&amp;nbsp;태그입니다.&amp;nbsp;심지어&amp;nbsp;기능&amp;nbsp;플래그를&amp;nbsp;구현할&amp;nbsp;수도&amp;nbsp;있습니다!&lt;br /&gt;&lt;br /&gt;프로필이&amp;nbsp;더&amp;nbsp;풍부해지면&amp;nbsp;통합&amp;nbsp;테스트에서&amp;nbsp;가끔씩&amp;nbsp;프로필을&amp;nbsp;바꾸고&amp;nbsp;싶을&amp;nbsp;때가&amp;nbsp;있습니다.&amp;nbsp;액티브&amp;nbsp;프로필과&amp;nbsp;같은&amp;nbsp;편리한&amp;nbsp;도구가&amp;nbsp;있습니다.&amp;nbsp;하지만&amp;nbsp;새&amp;nbsp;프로필로&amp;nbsp;테스트를&amp;nbsp;실행할&amp;nbsp;때마다&amp;nbsp;새&amp;nbsp;ApplicationContext가&amp;nbsp;생성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무것도&amp;nbsp;없는&amp;nbsp;바닐라&amp;nbsp;스프링&amp;nbsp;부팅&amp;nbsp;앱을&amp;nbsp;사용하면&amp;nbsp;애플리케이션&amp;nbsp;컨텍스트를&amp;nbsp;빠르게&amp;nbsp;생성할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;ORM과&amp;nbsp;몇&amp;nbsp;개의&amp;nbsp;모듈을&amp;nbsp;추가하면&amp;nbsp;7초&amp;nbsp;이상으로&amp;nbsp;빠르게&amp;nbsp;늘어납니다.&lt;br /&gt;&lt;br /&gt;여러&amp;nbsp;프로필을&amp;nbsp;추가하고&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;테스트를&amp;nbsp;통해&amp;nbsp;분산하면&amp;nbsp;60초&amp;nbsp;이상의&amp;nbsp;빌드를&amp;nbsp;빠르게&amp;nbsp;얻을&amp;nbsp;수&amp;nbsp;있습니다(빌드의&amp;nbsp;일부로&amp;nbsp;테스트를&amp;nbsp;실행한다는&amp;nbsp;가정&amp;nbsp;하에,&amp;nbsp;그리고&amp;nbsp;실제로&amp;nbsp;실행해야&amp;nbsp;합니다).&lt;br /&gt;&lt;br /&gt;일단&amp;nbsp;충분히&amp;nbsp;복잡한&amp;nbsp;애플리케이션에&amp;nbsp;직면하게&amp;nbsp;되면&amp;nbsp;이&amp;nbsp;문제를&amp;nbsp;해결하는&amp;nbsp;것은&amp;nbsp;매우&amp;nbsp;어렵습니다.&amp;nbsp;하지만&amp;nbsp;미리&amp;nbsp;신중하게&amp;nbsp;계획을&amp;nbsp;세운다면&amp;nbsp;합리적인&amp;nbsp;빌드&amp;nbsp;시간을&amp;nbsp;유지하는&amp;nbsp;것은&amp;nbsp;그리&amp;nbsp;어려운&amp;nbsp;일이&amp;nbsp;아닙니다.&lt;br /&gt;&lt;br /&gt;통합&amp;nbsp;테스트의&amp;nbsp;프로필과&amp;nbsp;관련하여&amp;nbsp;염두에&amp;nbsp;두어야&amp;nbsp;할&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;요령이&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;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;종합 프로필(예: 테스트)을 생성하고, 그 안에 필요한 모든 프로필을 포함하세요 - 어디에서나 테스트 프로필을 고수하세요.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;테스트 가능성을 염두에 두고 프로필을 디자인하세요. 프로필을 전환해야 하는 경우 더 나은 방법이 있을 수 있습니다.&lt;/li&gt;
&lt;li&gt;테스트 프로필을 중앙 집중식 장소에 명시하세요 - 이에 대해서는 나중에 설명하겠습니다.&lt;/li&gt;
&lt;li&gt;모든 프로필 조합을 테스트하지 마세요. 또는 특정 프로필 세트로 앱을 테스트하는 환경별 e2e 테스트 스위트를 만들 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;bd-2-the-problems-withmockbean&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;2-the-problems-withmockbean&quot; data-ke-size=&quot;size23&quot;&gt;4.2. The Problems with&amp;nbsp;@MockBean&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모의빈은&amp;nbsp;매우&amp;nbsp;강력한&amp;nbsp;도구입니다.&lt;br /&gt;&lt;br /&gt;Spring의&amp;nbsp;마법이&amp;nbsp;필요하지만&amp;nbsp;특정&amp;nbsp;컴포넌트를&amp;nbsp;모방하고&amp;nbsp;싶을&amp;nbsp;때&amp;nbsp;@MockBean은&amp;nbsp;매우&amp;nbsp;유용합니다.&amp;nbsp;하지만&amp;nbsp;대가가&amp;nbsp;따릅니다.&lt;br /&gt;&lt;br /&gt;클래스에서&amp;nbsp;@MockBean이&amp;nbsp;나타날&amp;nbsp;때마다&amp;nbsp;ApplicationContext&amp;nbsp;캐시가&amp;nbsp;더티로&amp;nbsp;표시되므로&amp;nbsp;테스트&amp;nbsp;클래스가&amp;nbsp;완료된&amp;nbsp;후&amp;nbsp;런너가&amp;nbsp;캐시를&amp;nbsp;정리합니다.&amp;nbsp;이는&amp;nbsp;다시&amp;nbsp;빌드에&amp;nbsp;몇&amp;nbsp;초를&amp;nbsp;더&amp;nbsp;추가합니다.&lt;br /&gt;&lt;br /&gt;이것은&amp;nbsp;논란의&amp;nbsp;여지가&amp;nbsp;있지만,&amp;nbsp;이&amp;nbsp;특정&amp;nbsp;시나리오에&amp;nbsp;대해&amp;nbsp;모의&amp;nbsp;테스트&amp;nbsp;대신&amp;nbsp;실제&amp;nbsp;앱을&amp;nbsp;실행해&amp;nbsp;보는&amp;nbsp;것이&amp;nbsp;도움이&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;물론&amp;nbsp;여기에&amp;nbsp;만병통치약은&amp;nbsp;없습니다.&amp;nbsp;종속성&amp;nbsp;모킹을&amp;nbsp;허용하지&amp;nbsp;않으면&amp;nbsp;경계가&amp;nbsp;모호해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트하고&amp;nbsp;싶은&amp;nbsp;것이&amp;nbsp;REST&amp;nbsp;계층뿐인데&amp;nbsp;왜&amp;nbsp;계속&amp;nbsp;테스트해야&amp;nbsp;하냐고&amp;nbsp;생각할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이는&amp;nbsp;타당한&amp;nbsp;지적이며,&amp;nbsp;항상&amp;nbsp;타협점이&amp;nbsp;존재합니다.&lt;br /&gt;&lt;br /&gt;하지만&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;원칙을&amp;nbsp;염두에&amp;nbsp;두면&amp;nbsp;테스트와&amp;nbsp;앱을&amp;nbsp;더&amp;nbsp;잘&amp;nbsp;설계하고&amp;nbsp;테스트&amp;nbsp;시간을&amp;nbsp;단축할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;이점으로&amp;nbsp;전환할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;bd-3-refactoringmockbean&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;3-refactoringmockbean&quot; data-ke-size=&quot;size23&quot;&gt;4.3. Refactoring&amp;nbsp;@MockBean&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;섹션에서는&amp;nbsp;@MockBean을&amp;nbsp;사용하여&amp;nbsp;'느린'&amp;nbsp;테스트를&amp;nbsp;리팩터링하여&amp;nbsp;캐시된&amp;nbsp;ApplicationContext를&amp;nbsp;재사용하도록&amp;nbsp;해&amp;nbsp;보겠습니다.&lt;br /&gt;&lt;br /&gt;사용자를&amp;nbsp;생성하는&amp;nbsp;POST를&amp;nbsp;테스트하고&amp;nbsp;싶다고&amp;nbsp;가정해&amp;nbsp;보겠습니다.&amp;nbsp;모의&amp;nbsp;테스트에서&amp;nbsp;@MockBean을&amp;nbsp;사용하면&amp;nbsp;서비스가&amp;nbsp;제대로&amp;nbsp;직렬화된&amp;nbsp;사용자로&amp;nbsp;호출되었는지&amp;nbsp;간단히&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;서비스를&amp;nbsp;제대로&amp;nbsp;테스트했다면&amp;nbsp;이&amp;nbsp;방법으로도&amp;nbsp;충분할&amp;nbsp;것입니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만&amp;nbsp;@MockBean은&amp;nbsp;피하고&amp;nbsp;싶습니다.&amp;nbsp;따라서&amp;nbsp;결국&amp;nbsp;엔티티를&amp;nbsp;유지하게&amp;nbsp;될&amp;nbsp;것입니다(서비스가&amp;nbsp;그렇게&amp;nbsp;한다고&amp;nbsp;가정할&amp;nbsp;때).&lt;br /&gt;&lt;br /&gt;여기서&amp;nbsp;가장&amp;nbsp;순진한&amp;nbsp;접근&amp;nbsp;방식은&amp;nbsp;부작용을&amp;nbsp;테스트하는&amp;nbsp;것입니다:&amp;nbsp;게시&amp;nbsp;후&amp;nbsp;내&amp;nbsp;사용자는&amp;nbsp;내&amp;nbsp;DB에&amp;nbsp;있으며,&amp;nbsp;이&amp;nbsp;예제에서는&amp;nbsp;JDBC를&amp;nbsp;사용합니다.&lt;br /&gt;&lt;br /&gt;그러나&amp;nbsp;이는&amp;nbsp;테스트&amp;nbsp;경계를&amp;nbsp;위반하는&amp;nbsp;것입니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;특정&amp;nbsp;예제에서는&amp;nbsp;사용자를&amp;nbsp;전송하기&amp;nbsp;위해&amp;nbsp;앱을&amp;nbsp;HTTP&amp;nbsp;블랙박스로&amp;nbsp;취급하지만&amp;nbsp;나중에&amp;nbsp;구현&amp;nbsp;세부&amp;nbsp;정보,&amp;nbsp;즉&amp;nbsp;사용자가&amp;nbsp;일부&amp;nbsp;DB에&amp;nbsp;지속되었다고&amp;nbsp;주장하기&amp;nbsp;때문에&amp;nbsp;테스트&amp;nbsp;경계를&amp;nbsp;위반합니다.&lt;br /&gt;&lt;br /&gt;HTTP를&amp;nbsp;통해&amp;nbsp;앱을&amp;nbsp;실행하면&amp;nbsp;결과도&amp;nbsp;HTTP를&amp;nbsp;통해&amp;nbsp;어설트할&amp;nbsp;수&amp;nbsp;있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막&amp;nbsp;접근&amp;nbsp;방식을&amp;nbsp;따르는&amp;nbsp;경우&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;장점이&amp;nbsp;있습니다:&lt;br /&gt;&lt;br /&gt;테스트가&amp;nbsp;더&amp;nbsp;빨리&amp;nbsp;시작됩니다(실행하는&amp;nbsp;데&amp;nbsp;시간이&amp;nbsp;조금&amp;nbsp;더&amp;nbsp;걸릴&amp;nbsp;수&amp;nbsp;있지만,&amp;nbsp;그만한&amp;nbsp;가치가&amp;nbsp;있습니다).&lt;br /&gt;또한,&amp;nbsp;테스트는&amp;nbsp;HTTP&amp;nbsp;경계와&amp;nbsp;관련이&amp;nbsp;없는&amp;nbsp;부작용(예:&amp;nbsp;DB)을&amp;nbsp;인식하지&amp;nbsp;못합니다.&lt;br /&gt;마지막으로,&amp;nbsp;이&amp;nbsp;테스트는&amp;nbsp;시스템의&amp;nbsp;의도를&amp;nbsp;명확하게&amp;nbsp;표현합니다:&amp;nbsp;POST하면&amp;nbsp;GET&amp;nbsp;사용자가&amp;nbsp;가능합니다.&lt;br /&gt;물론&amp;nbsp;여러&amp;nbsp;가지&amp;nbsp;이유로&amp;nbsp;항상&amp;nbsp;가능하지&amp;nbsp;않을&amp;nbsp;수도&amp;nbsp;있습니다:&lt;br /&gt;&lt;br /&gt;'부작용'&amp;nbsp;엔드포인트가&amp;nbsp;없을&amp;nbsp;수도&amp;nbsp;있습니다:&amp;nbsp;여기서&amp;nbsp;한&amp;nbsp;가지&amp;nbsp;옵션은&amp;nbsp;'테스트&amp;nbsp;엔드포인트'&amp;nbsp;생성을&amp;nbsp;고려하는&amp;nbsp;것입니다.&lt;br /&gt;앱&amp;nbsp;전체에&amp;nbsp;적용하기에는&amp;nbsp;복잡성이&amp;nbsp;너무&amp;nbsp;높은&amp;nbsp;경우:&amp;nbsp;슬라이스를&amp;nbsp;고려하는&amp;nbsp;옵션이&amp;nbsp;있습니다(이에&amp;nbsp;대해서는&amp;nbsp;나중에&amp;nbsp;설명하겠습니다).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;bd-4-thinking-carefully-about-dirtiescontext&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;4-thinking-carefully-about-dirtiescontext&quot; data-ke-size=&quot;size23&quot;&gt;4.4. Thinking Carefully About&lt;span&gt;&amp;nbsp;&lt;/span&gt;@DirtiesContext&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때때로&amp;nbsp;테스트에서&amp;nbsp;ApplicationContext를&amp;nbsp;수정해야&amp;nbsp;할&amp;nbsp;수도&amp;nbsp;있습니다.&amp;nbsp;이&amp;nbsp;시나리오의&amp;nbsp;경우&amp;nbsp;@DirtiesContext가&amp;nbsp;정확히&amp;nbsp;그&amp;nbsp;기능을&amp;nbsp;제공합니다.&lt;br /&gt;&lt;br /&gt;위에서&amp;nbsp;설명한&amp;nbsp;것과&amp;nbsp;같은&amp;nbsp;이유로&amp;nbsp;@DirtiesContext는&amp;nbsp;실행&amp;nbsp;시간&amp;nbsp;측면에서&amp;nbsp;매우&amp;nbsp;비싼&amp;nbsp;리소스이므로&amp;nbsp;주의해야&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;애플리케이션&amp;nbsp;캐시&amp;nbsp;재설정&amp;nbsp;또는&amp;nbsp;메모리&amp;nbsp;내&amp;nbsp;DB&amp;nbsp;재설정을&amp;nbsp;위해&amp;nbsp;@DirtiesContext를&amp;nbsp;오용하는&amp;nbsp;경우도&amp;nbsp;있습니다.&amp;nbsp;통합&amp;nbsp;테스트에서&amp;nbsp;이러한&amp;nbsp;시나리오를&amp;nbsp;처리하는&amp;nbsp;더&amp;nbsp;좋은&amp;nbsp;방법이&amp;nbsp;있으며,&amp;nbsp;다음&amp;nbsp;섹션에서&amp;nbsp;몇&amp;nbsp;가지를&amp;nbsp;다룰&amp;nbsp;것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;bd-5-using-test-slices&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;5-using-test-slices&quot; data-ke-size=&quot;size23&quot;&gt;4.5. Using Test Slices&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트&amp;nbsp;슬라이스는&amp;nbsp;1.4에&amp;nbsp;도입된&amp;nbsp;Spring&amp;nbsp;Boot&amp;nbsp;기능입니다.&amp;nbsp;개념은&amp;nbsp;매우&amp;nbsp;간단합니다.&amp;nbsp;Spring은&amp;nbsp;앱의&amp;nbsp;특정&amp;nbsp;슬라이스에&amp;nbsp;대해&amp;nbsp;축소된&amp;nbsp;애플리케이션&amp;nbsp;컨텍스트를&amp;nbsp;생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한&amp;nbsp;프레임워크는&amp;nbsp;최소한의&amp;nbsp;구성만&amp;nbsp;처리합니다.&lt;br /&gt;&lt;br /&gt;Spring&amp;nbsp;Boot에는&amp;nbsp;기본적으로&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;적절한&amp;nbsp;수의&amp;nbsp;슬라이스가&amp;nbsp;있으며,&amp;nbsp;자체&amp;nbsp;슬라이스를&amp;nbsp;만들&amp;nbsp;수도&amp;nbsp;있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;@JsonTest: JSON 관련 컴포넌트를 등록합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;@DataJpaTest: 사용 가능한 ORM을 포함한 JPA 빈을 등록합니다.&lt;/li&gt;
&lt;li&gt;@JdbcTest: 원시 JDBC 테스트에 유용하며, 데이터 소스 및 메모리 내 DB를 ORM 없이 처리합니다.&lt;/li&gt;
&lt;li&gt;데이터몽고테스트: 인메모리 몽고 테스트 설정을 제공하려고 시도합니다.&lt;/li&gt;
&lt;li&gt;WebMvcTest: 앱의 나머지 부분이 없는 모의 MVC 테스트 슬라이스&lt;/li&gt;
&lt;li&gt;... (소스를 확인하여 모두 찾을 수 있음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;기능을&amp;nbsp;현명하게&amp;nbsp;사용하면&amp;nbsp;특히&amp;nbsp;중소규모&amp;nbsp;앱의&amp;nbsp;경우&amp;nbsp;성능&amp;nbsp;측면에서&amp;nbsp;큰&amp;nbsp;불이익&amp;nbsp;없이&amp;nbsp;좁은&amp;nbsp;범위의&amp;nbsp;테스트를&amp;nbsp;구축하는&amp;nbsp;데&amp;nbsp;도움이&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;하지만&amp;nbsp;애플리케이션이&amp;nbsp;계속&amp;nbsp;커지면&amp;nbsp;슬라이스당&amp;nbsp;하나의&amp;nbsp;(작은)&amp;nbsp;애플리케이션&amp;nbsp;컨텍스트가&amp;nbsp;생성되므로&amp;nbsp;이&amp;nbsp;또한&amp;nbsp;쌓이게&amp;nbsp;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;bd-6-using-class-inheritance&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;6-using-class-inheritance&quot; data-ke-size=&quot;size23&quot;&gt;4.6. Using Class Inheritance&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든&amp;nbsp;통합&amp;nbsp;테스트의&amp;nbsp;부모로&amp;nbsp;단일&amp;nbsp;AbstractSpringIntegrationTest&amp;nbsp;클래스를&amp;nbsp;사용하는&amp;nbsp;것은&amp;nbsp;빌드를&amp;nbsp;빠르게&amp;nbsp;유지하는&amp;nbsp;간단하고&amp;nbsp;강력하며&amp;nbsp;실용적인&amp;nbsp;방법입니다.&lt;br /&gt;&lt;br /&gt;우리가&amp;nbsp;탄탄한&amp;nbsp;설정을&amp;nbsp;제공하면,&amp;nbsp;우리&amp;nbsp;팀은&amp;nbsp;모든&amp;nbsp;것이&amp;nbsp;'그냥&amp;nbsp;작동'한다는&amp;nbsp;것을&amp;nbsp;알고&amp;nbsp;간단히&amp;nbsp;확장할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이렇게&amp;nbsp;하면&amp;nbsp;상태&amp;nbsp;관리나&amp;nbsp;프레임워크&amp;nbsp;구성에&amp;nbsp;대한&amp;nbsp;걱정을&amp;nbsp;덜고&amp;nbsp;당면한&amp;nbsp;문제에&amp;nbsp;집중할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;모든&amp;nbsp;테스트&amp;nbsp;요구&amp;nbsp;사항을&amp;nbsp;설정할&amp;nbsp;수&amp;nbsp;있습니다:&lt;br /&gt;&lt;br /&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;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Spring 주자 - 나중에 다른 주자가 필요할 경우를 대비해 규칙을 설정하는 것이 좋습니다.&lt;/span&gt;&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;br /&gt;앞의&amp;nbsp;사항을&amp;nbsp;처리하는&amp;nbsp;간단한&amp;nbsp;베이스&amp;nbsp;클래스를&amp;nbsp;살펴봅시다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;bd-7-state-management&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;7-state-management&quot; data-ke-size=&quot;size23&quot;&gt;4.7. State Management&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단위&amp;nbsp;테스트의&amp;nbsp;'단위'가&amp;nbsp;어디에서&amp;nbsp;왔는지&amp;nbsp;기억하는&amp;nbsp;것이&amp;nbsp;중요합니다.&amp;nbsp;간단히&amp;nbsp;말해,&amp;nbsp;단일&amp;nbsp;테스트(또는&amp;nbsp;하위&amp;nbsp;집합)를&amp;nbsp;언제든지&amp;nbsp;실행하여&amp;nbsp;일관된&amp;nbsp;결과를&amp;nbsp;얻을&amp;nbsp;수&amp;nbsp;있다는&amp;nbsp;뜻입니다.&lt;br /&gt;&lt;br /&gt;따라서&amp;nbsp;모든&amp;nbsp;테스트가&amp;nbsp;시작되기&amp;nbsp;전에&amp;nbsp;상태가&amp;nbsp;깨끗하고&amp;nbsp;알려져&amp;nbsp;있어야&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;즉,&amp;nbsp;테스트가&amp;nbsp;단독으로&amp;nbsp;실행되든&amp;nbsp;다른&amp;nbsp;테스트와&amp;nbsp;함께&amp;nbsp;실행되든&amp;nbsp;관계없이&amp;nbsp;테스트&amp;nbsp;결과가&amp;nbsp;일관적이어야&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;이&amp;nbsp;아이디어는&amp;nbsp;통합&amp;nbsp;테스트에도&amp;nbsp;동일하게&amp;nbsp;적용됩니다.&amp;nbsp;새&amp;nbsp;테스트를&amp;nbsp;시작하기&amp;nbsp;전에&amp;nbsp;앱이&amp;nbsp;알려진(그리고&amp;nbsp;반복&amp;nbsp;가능한)&amp;nbsp;상태인지&amp;nbsp;확인해야&amp;nbsp;합니다.&amp;nbsp;속도를&amp;nbsp;높이기&amp;nbsp;위해&amp;nbsp;재사용하는&amp;nbsp;구성&amp;nbsp;요소(앱&amp;nbsp;컨텍스트,&amp;nbsp;DB,&amp;nbsp;대기열,&amp;nbsp;파일&amp;nbsp;등)가&amp;nbsp;많을수록&amp;nbsp;상태&amp;nbsp;오염이&amp;nbsp;발생할&amp;nbsp;가능성이&amp;nbsp;높아집니다.&lt;br /&gt;&lt;br /&gt;클래스&amp;nbsp;상속을&amp;nbsp;사용했다고&amp;nbsp;가정하면&amp;nbsp;이제&amp;nbsp;상태를&amp;nbsp;관리할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;중앙&amp;nbsp;집중식&amp;nbsp;공간이&amp;nbsp;생겼습니다.&lt;br /&gt;&lt;br /&gt;테스트를&amp;nbsp;실행하기&amp;nbsp;전에&amp;nbsp;앱이&amp;nbsp;알려진&amp;nbsp;상태에&amp;nbsp;있는지&amp;nbsp;확인하기&amp;nbsp;위해&amp;nbsp;추상&amp;nbsp;클래스를&amp;nbsp;개선해&amp;nbsp;보겠습니다.&lt;br /&gt;&lt;br /&gt;이&amp;nbsp;예제에서는&amp;nbsp;다양한&amp;nbsp;데이터&amp;nbsp;소스의&amp;nbsp;여러&amp;nbsp;리포지토리와&amp;nbsp;와이어목&amp;nbsp;서버가&amp;nbsp;있다고&amp;nbsp;가정하겠습니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;bd-8-refactoring-into-unit-tests&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-id=&quot;8-refactoring-into-unit-tests&quot; data-ke-size=&quot;size23&quot;&gt;4.8. Refactoring into Unit Tests&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이&amp;nbsp;아마도&amp;nbsp;가장&amp;nbsp;중요한&amp;nbsp;포인트&amp;nbsp;중&amp;nbsp;하나일&amp;nbsp;것입니다.&amp;nbsp;실제로&amp;nbsp;앱의&amp;nbsp;상위&amp;nbsp;정책을&amp;nbsp;실행하는&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;통합&amp;nbsp;테스트를&amp;nbsp;반복해서&amp;nbsp;수행하게&amp;nbsp;될&amp;nbsp;것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심&amp;nbsp;비즈니스&amp;nbsp;로직의&amp;nbsp;여러&amp;nbsp;사례를&amp;nbsp;테스트하는&amp;nbsp;통합&amp;nbsp;테스트를&amp;nbsp;발견할&amp;nbsp;때마다&amp;nbsp;접근&amp;nbsp;방식을&amp;nbsp;재고하고&amp;nbsp;단위&amp;nbsp;테스트로&amp;nbsp;세분화해야&amp;nbsp;할&amp;nbsp;때입니다.&lt;br /&gt;&lt;br /&gt;이를&amp;nbsp;성공적으로&amp;nbsp;수행하기&amp;nbsp;위한&amp;nbsp;가능한&amp;nbsp;패턴은&amp;nbsp;다음과&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;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;핵심 비즈니스 로직의 여러 시나리오를 테스트하는 통합 테스트를 식별합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;제품군을 복제하고 복사본을 단위 테스트로 리팩터링 - 이 단계에서는 프로덕션 코드도 테스트할 수 있도록 세분화해야 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;모든 테스트를 녹색으로 설정&lt;/li&gt;
&lt;li&gt;통합 제품군에서 충분히 주목할 만한 행복한 경로 샘플을 남겨둡니다 - 몇 가지를 리팩터링하거나 조인 및 재구성해야 할 수도 있습니다.&lt;/li&gt;
&lt;li&gt;나머지 통합 테스트 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-Java</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742110</guid>
      <comments>https://sojw.tistory.com/1169742110#entry1169742110comment</comments>
      <pubDate>Sun, 26 Nov 2023 01:13:08 +0900</pubDate>
    </item>
    <item>
      <title>transaction isolation level</title>
      <link>https://sojw.tistory.com/1169742109</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HwRta/btszJHFYKwR/Isjh2iu98KDkvO9h8L0710/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HwRta/btszJHFYKwR/Isjh2iu98KDkvO9h8L0710/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HwRta/btszJHFYKwR/Isjh2iu98KDkvO9h8L0710/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHwRta%2FbtszJHFYKwR%2FIsjh2iu98KDkvO9h8L0710%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;598&quot; height=&quot;196&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 업무를 하다 보면 기본적 level만 사용하기 때문에. (특별한 domain logic 처리가 요구 되지 않는한.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 level들을 기억하기 쉽지 않다. 그렇다고 안 중요한 부분도 아니라서 세부내용은 그때 그때 찾아 볼수 있게 해두는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 blogging...&lt;/p&gt;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742109</guid>
      <comments>https://sojw.tistory.com/1169742109#entry1169742109comment</comments>
      <pubDate>Sat, 4 Nov 2023 23:43:29 +0900</pubDate>
    </item>
    <item>
      <title>meeting : where to go?</title>
      <link>https://sojw.tistory.com/1169742108</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 했던 meeting들을 돌이켜 보면서 문득 스친 생각들을 적어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;key point(warm up) -&amp;gt; discussion -&amp;gt; decision making -&amp;gt; summary text&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;meeting의 목적은 여러 이유가 있을 수 있겠지만,&lt;br /&gt;내가 참여하는 부분에서는 어떤 이슈에 대한 공유나 크던 작던 의사결정이 대부분이다.&lt;br /&gt;그 외에 주제들은 다른 커뮤니케이션 도구들로 공유가 되게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, 최근의 meeting들도 특정한 주제에 대한 논의들이 대부분이었고,&lt;br /&gt;실제 어떤 이슈가 있었고, 어떤 방식으로 풀어 나갈지 의견을 교환을 했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 조금 잘 하지 못하거나 아쉬웠던 점들은&lt;br /&gt;이 논의가 브레인스토밍 형태로 다양한 방법을 만드는데 목적인지?&lt;br /&gt;지금 겪고 있는 이슈들에 대한 처리나 대응에 대한 의사결정이 목적인지?&lt;br /&gt; 과도한 issue one-shot 처리를 위한 meeting 이었는지?&lt;br /&gt;....... 등등&lt;br /&gt;위 물음에 대한 적절한 흐름으로 원하는 형태로 잘 도출 되었는지에 대한 인식이 부족했던 지점이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서,&amp;nbsp;&lt;br /&gt;meeting의 간략한 key point를 시작 전에 인지 할 수 있는 warm up이 필요하고,&lt;br /&gt;애초에 목표한 성격으로 논의가 잘 진행 되게 컨트롤 하여야 하고,&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;meeting의 완료 될 시점에 분명한 텍스트가 정리가 되어서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&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;meeting의 무척 중요한 지점은 여러 참가자의 resource를 필요로 하기 때문이다.&lt;br /&gt;그렇기 때문에 덜 준비 된 meeting내용과 참여자들의 불성실함들은 meeting무용론이 나오기 딱 좋은 원인이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수려하게 잘 정리 되는 것이 목적이 아닌,&lt;br /&gt;적어도 참여자들이 최종적으로 논의/동의한 내용이 이해 할 수 있는 수준의 텍스트로만 정리가 되어도&lt;br /&gt;그 meeting은 앞으로의 업무나 여러 여정에 큰 도움이 될 것이라 확신 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>ing.</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742108</guid>
      <comments>https://sojw.tistory.com/1169742108#entry1169742108comment</comments>
      <pubDate>Wed, 1 Nov 2023 01:30:53 +0900</pubDate>
    </item>
    <item>
      <title>A guide to input validation with Spring Boot</title>
      <link>https://sojw.tistory.com/1169742107</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@snyksec/a-guide-to-input-validation-with-spring-boot-f041b19c82e6&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@snyksec/a-guide-to-input-validation-with-spring-boot-f041b19c82e6&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; href=&quot;https://medium.com/@snyksec/a-guide-to-input-validation-with-spring-boot-f041b19c82e6?source=email-cdbbdddc72cf-1698339721451-digest.reader--f041b19c82e6----2-98------------------8273968e_7f58_4605_95dc_87bf3d6db8b2-1&quot; data-saferedirecturl=&quot;https://www.google.com/url?q=https://medium.com/@snyksec/a-guide-to-input-validation-with-spring-boot-f041b19c82e6?source%3Demail-cdbbdddc72cf-1698339721451-digest.reader--f041b19c82e6----2-98------------------8273968e_7f58_4605_95dc_87bf3d6db8b2-1&amp;amp;source=gmail&amp;amp;ust=1698506383610000&amp;amp;usg=AOvVaw33zFvU6-x0lWHZOUzEV-hA&quot;&gt;
&lt;div&gt;
&lt;div style=&quot;color: #292929;&quot;&gt;&lt;b&gt;A guide to input validation with Spring Boot&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;스프링&amp;nbsp;부트&amp;nbsp;빈&amp;nbsp;유효성&amp;nbsp;검사&amp;nbsp;구현하기&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이&amp;nbsp;튜토리얼에서는&amp;nbsp;인메모리&amp;nbsp;데이터베이스를&amp;nbsp;사용하는&amp;nbsp;간단한&amp;nbsp;CRUD(생성,&amp;nbsp;읽기,&amp;nbsp;업데이트,&amp;nbsp;삭제)&amp;nbsp;애플리케이션에&amp;nbsp;대한&amp;nbsp;Bean&amp;nbsp;유효성&amp;nbsp;검사를&amp;nbsp;구현합니다.&amp;nbsp;사용자는&amp;nbsp;이름,&amp;nbsp;이메일&amp;nbsp;및&amp;nbsp;비밀번호를&amp;nbsp;제공하며,&amp;nbsp;특정&amp;nbsp;기준을&amp;nbsp;충족해야&amp;nbsp;허용됩니다.&amp;nbsp;여기서&amp;nbsp;사용되는&amp;nbsp;상위&amp;nbsp;수준&amp;nbsp;아키텍처는&amp;nbsp;RESTful&amp;nbsp;API가&amp;nbsp;포함된&amp;nbsp;백엔드&amp;nbsp;서버와&amp;nbsp;인메모리&amp;nbsp;H2&amp;nbsp;데이터베이스로&amp;nbsp;구성됩니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;클라이언트&amp;nbsp;애플리케이션이&amp;nbsp;웹&amp;nbsp;서비스(이&amp;nbsp;튜토리얼의&amp;nbsp;애플리케이션)를&amp;nbsp;호출하면&amp;nbsp;요청이&amp;nbsp;UserController로&amp;nbsp;전달됩니다.&amp;nbsp;그&amp;nbsp;후&amp;nbsp;컨트롤러는&amp;nbsp;요청에&amp;nbsp;데이터&amp;nbsp;유효성&amp;nbsp;검사를&amp;nbsp;적용합니다.&amp;nbsp;데이터가&amp;nbsp;유효하면&amp;nbsp;요청은&amp;nbsp;UserRepository로&amp;nbsp;이동하여&amp;nbsp;인메모리&amp;nbsp;데이터베이스와&amp;nbsp;통신하고&amp;nbsp;관련&amp;nbsp;응답을&amp;nbsp;반환합니다.&amp;nbsp;그렇지&amp;nbsp;않으면&amp;nbsp;데이터가&amp;nbsp;유효하지&amp;nbsp;않으며&amp;nbsp;요청은&amp;nbsp;오류&amp;nbsp;메시지와&amp;nbsp;함께&amp;nbsp;클라이언트로&amp;nbsp;다시&amp;nbsp;전송됩니다:&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&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;1400&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s5UL3/btszgy4nuVR/mIElIPQwtvfokaGa6KQlvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s5UL3/btszgy4nuVR/mIElIPQwtvfokaGa6KQlvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s5UL3/btszgy4nuVR/mIElIPQwtvfokaGa6KQlvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs5UL3%2Fbtszgy4nuVR%2FmIElIPQwtvfokaGa6KQlvK%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;1400&quot; height=&quot;654&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;654&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;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742107</guid>
      <comments>https://sojw.tistory.com/1169742107#entry1169742107comment</comments>
      <pubDate>Sat, 28 Oct 2023 00:58:43 +0900</pubDate>
    </item>
    <item>
      <title>Monitoring Spring Boot 3</title>
      <link>https://sojw.tistory.com/1169742106</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Springboot 3이 출시 되면서, 기존 하위 버전이하를 포함해서 모니터링 관련 내용을 되새겨 볼만한 포스트.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@minadev/monitoring-and-observability-with-spring-boot-3-2cb9cdb74a85&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@minadev/monitoring-and-observability-with-spring-boot-3-2cb9cdb74a85&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742106</guid>
      <comments>https://sojw.tistory.com/1169742106#entry1169742106comment</comments>
      <pubDate>Sat, 28 Oct 2023 00:50:08 +0900</pubDate>
    </item>
    <item>
      <title>API Architectural Styles</title>
      <link>https://sojw.tistory.com/1169742105</link>
      <description>&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://medium.com/@saadmujeeb/the-ultimate-guide-to-api-architectural-styles-c8c781014835&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@saadmujeeb/the-ultimate-guide-to-api-architectural-styles-c8c781014835&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1695175799736&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;The Ultimate Guide to API Architectural Styles&quot; data-og-description=&quot;Discover the top API architectural styles &amp;mdash; SOAP, REST, GraphQL, gRPC, WebSocket, and Webhook &amp;mdash; in this comprehensive, engaging guide.&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@saadmujeeb/the-ultimate-guide-to-api-architectural-styles-c8c781014835&quot; data-og-url=&quot;https://medium.com/@saadmujeeb/the-ultimate-guide-to-api-architectural-styles-c8c781014835&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bSwrLL/hyTYZFdiI3/hT9Iq7w8K4E5DM2RnseGw1/img.jpg?width=1200&amp;amp;height=640&amp;amp;face=0_0_1200_640&quot;&gt;&lt;a href=&quot;https://medium.com/@saadmujeeb/the-ultimate-guide-to-api-architectural-styles-c8c781014835&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@saadmujeeb/the-ultimate-guide-to-api-architectural-styles-c8c781014835&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bSwrLL/hyTYZFdiI3/hT9Iq7w8K4E5DM2RnseGw1/img.jpg?width=1200&amp;amp;height=640&amp;amp;face=0_0_1200_640');&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 Ultimate Guide to API Architectural Styles&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Discover the top API architectural styles &amp;mdash; SOAP, REST, GraphQL, gRPC, WebSocket, and Webhook &amp;mdash; in this comprehensive, engaging guide.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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://www.linkedin.com/posts/nelsonamigoscode_systemdesign-coding-interviewtips-activity-7107264125214277633-uW1E/?utm_source=share&amp;amp;utm_medium=member_ios&quot;&gt;https://www.linkedin.com/posts/nelsonamigoscode_systemdesign-coding-interviewtips-activity-7107264125214277633-uW1E/?utm_source=share&amp;amp;utm_medium=member_ios&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1695175823801&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;LinkedIn Nelson Djalo 페이지: #systemdesign #coding #interviewtips | 댓글 98&quot; data-og-description=&quot;6️⃣&amp;nbsp;Popular API Architecture Styles 1. gRPC: A high-performance, language-agnostic remote procedure call (RPC) framework for efficient communication between&amp;hellip; | 댓글 98&quot; data-og-host=&quot;www.linkedin.com&quot; data-og-source-url=&quot;https://www.linkedin.com/posts/nelsonamigoscode_systemdesign-coding-interviewtips-activity-7107264125214277633-uW1E/?utm_source=share&amp;amp;utm_medium=member_ios&quot; data-og-url=&quot;https://www.linkedin.com/posts/nelsonamigoscode_systemdesign-coding-interviewtips-activity-7107264125214277633-uW1E&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ckjRVk/hyTVQiRVsK/Sfd1HoIpPnGEdehc9ZHTP0/img.gif?width=1120&amp;amp;height=1360&amp;amp;face=0_0_1120_1360,https://scrap.kakaocdn.net/dn/yYZ5X/hyTY2IIvYB/nDhWrKCU5KI2VODjIHREU1/img.gif?width=1120&amp;amp;height=1360&amp;amp;face=0_0_1120_1360&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/posts/nelsonamigoscode_systemdesign-coding-interviewtips-activity-7107264125214277633-uW1E/?utm_source=share&amp;amp;utm_medium=member_ios&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.linkedin.com/posts/nelsonamigoscode_systemdesign-coding-interviewtips-activity-7107264125214277633-uW1E/?utm_source=share&amp;amp;utm_medium=member_ios&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ckjRVk/hyTVQiRVsK/Sfd1HoIpPnGEdehc9ZHTP0/img.gif?width=1120&amp;amp;height=1360&amp;amp;face=0_0_1120_1360,https://scrap.kakaocdn.net/dn/yYZ5X/hyTY2IIvYB/nDhWrKCU5KI2VODjIHREU1/img.gif?width=1120&amp;amp;height=1360&amp;amp;face=0_0_1120_1360');&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;LinkedIn Nelson Djalo 페이지: #systemdesign #coding #interviewtips | 댓글 98&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;6️⃣&amp;nbsp;Popular API Architecture Styles 1. gRPC: A high-performance, language-agnostic remote procedure call (RPC) framework for efficient communication between&amp;hellip; | 댓글 98&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.linkedin.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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;971&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yn2XO/btsuqz7VJ1C/Lt66E4EV5Ao6WPZ51BEiWK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yn2XO/btsuqz7VJ1C/Lt66E4EV5Ao6WPZ51BEiWK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yn2XO/btsuqz7VJ1C/Lt66E4EV5Ao6WPZ51BEiWK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/Yn2XO/btsuqz7VJ1C/Lt66E4EV5Ao6WPZ51BEiWK/img.gif&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;971&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;971&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;p data-ke-size=&quot;size16&quot;&gt;1.&amp;nbsp;gRPC:&amp;nbsp;분산&amp;nbsp;시스템&amp;nbsp;간의&amp;nbsp;효율적인&amp;nbsp;통신을&amp;nbsp;위한&amp;nbsp;고성능,&amp;nbsp;언어에&amp;nbsp;구애받지&amp;nbsp;않는&amp;nbsp;원격&amp;nbsp;프로시저&amp;nbsp;호출(RPC)&amp;nbsp;프레임워크로,&amp;nbsp;마이크로서비스&amp;nbsp;아키텍처에서&amp;nbsp;자주&amp;nbsp;사용됩니다.&lt;br /&gt;&lt;br /&gt;2.&amp;nbsp;SOAP:&amp;nbsp;웹&amp;nbsp;서비스&amp;nbsp;구현&amp;nbsp;시&amp;nbsp;구조화된&amp;nbsp;정보를&amp;nbsp;교환하기&amp;nbsp;위한&amp;nbsp;프로토콜로,&amp;nbsp;엄격한&amp;nbsp;표준과&amp;nbsp;XML&amp;nbsp;기반&amp;nbsp;메시지&amp;nbsp;형식으로&amp;nbsp;유명합니다.&lt;br /&gt;&lt;br /&gt;3.&amp;nbsp;GraphQL:&amp;nbsp;클라이언트가&amp;nbsp;필요한&amp;nbsp;데이터만&amp;nbsp;요청할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;하여&amp;nbsp;데이터의&amp;nbsp;과다&amp;nbsp;가져오기&amp;nbsp;및&amp;nbsp;과소&amp;nbsp;가져오기를&amp;nbsp;줄여주는&amp;nbsp;API용&amp;nbsp;쿼리&amp;nbsp;언어&amp;nbsp;및&amp;nbsp;런타임입니다.&lt;br /&gt;&lt;br /&gt;4.&amp;nbsp;웹후크:&amp;nbsp;애플리케이션이&amp;nbsp;미리&amp;nbsp;정의된&amp;nbsp;URL로&amp;nbsp;HTTP&amp;nbsp;POST&amp;nbsp;요청을&amp;nbsp;전송하여&amp;nbsp;다른&amp;nbsp;시스템에서&amp;nbsp;작업을&amp;nbsp;알리고&amp;nbsp;트리거하는&amp;nbsp;실시간&amp;nbsp;통신&amp;nbsp;메커니즘입니다.&lt;br /&gt;&lt;br /&gt;5.&amp;nbsp;REST:&amp;nbsp;네트워크&amp;nbsp;애플리케이션을&amp;nbsp;설계하기&amp;nbsp;위한&amp;nbsp;아키텍처&amp;nbsp;스타일로,&amp;nbsp;리소스를&amp;nbsp;조작하기&amp;nbsp;위해&amp;nbsp;표준&amp;nbsp;HTTP&amp;nbsp;메서드(GET,&amp;nbsp;POST,&amp;nbsp;PUT,&amp;nbsp;DELETE)를&amp;nbsp;사용하는&amp;nbsp;표현&amp;nbsp;상태&amp;nbsp;전송입니다.&lt;br /&gt;&lt;br /&gt;6.&amp;nbsp;웹소켓:&amp;nbsp;수명이&amp;nbsp;긴&amp;nbsp;단일&amp;nbsp;연결을&amp;nbsp;통해&amp;nbsp;클라이언트와&amp;nbsp;서버&amp;nbsp;간의&amp;nbsp;양방향&amp;nbsp;실시간&amp;nbsp;통신을&amp;nbsp;가능하게&amp;nbsp;하는&amp;nbsp;프로토콜로,&amp;nbsp;채팅이나&amp;nbsp;게임과&amp;nbsp;같이&amp;nbsp;지연&amp;nbsp;시간이&amp;nbsp;짧은&amp;nbsp;업데이트가&amp;nbsp;필요한&amp;nbsp;애플리케이션에&amp;nbsp;이상적입니다.&lt;/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>emotional developer/detect-Web</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742105</guid>
      <comments>https://sojw.tistory.com/1169742105#entry1169742105comment</comments>
      <pubDate>Wed, 20 Sep 2023 11:11:12 +0900</pubDate>
    </item>
    <item>
      <title>How To Github Actions Local Test</title>
      <link>https://sojw.tistory.com/1169742103</link>
      <description>&lt;h1 id=&quot;act&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1&quot;&gt;&lt;b&gt;act&lt;/b&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-inline-card=&quot;true&quot; data-card-url=&quot;https://github.com/nektos/act&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span data-testid=&quot;hover-card-trigger-wrapper&quot;&gt;&lt;a href=&quot;https://github.com/nektos/act&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/nektos/act&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;local 환경에서 github actions을 테스트 할 수 환경 구성&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/nektos/act#first-act-run&quot; data-testid=&quot;link-with-safety&quot; data-renderer-mark=&quot;true&quot;&gt;First act run&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/nektos/act#github_token&quot; data-testid=&quot;link-with-safety&quot; data-renderer-mark=&quot;true&quot;&gt;GITHUB_TOKEN&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;3&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;gitbug token기반으로 github와 연결되어 있는 경우, 추가적인 shell option 필요&lt;/li&gt;
&lt;li&gt;shell act -s GITHUB_TOKEN=&quot;$(gh auth token)&quot; : github cli 방식 선호, gh 설치 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/nektos/act#secrets&quot; data-testid=&quot;link-with-safety&quot; data-renderer-mark=&quot;true&quot;&gt;Secrets&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;shell act --secret-file my.secrets : my.secrets 파일 내에 secret 변수 선언
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;3&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) my.secrets -&amp;gt; SLACK_WEBHOOK_URL=xxxxxxxxxxxxxx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;act-local-test-shell&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;372&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;act local test shell&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1692372348167&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Test 대상 git repository root 위치에서 아래 shell 실행

// 1. actions 목록조회
act -l
act -l --container-architecture linux/amd64 &amp;lt;- mac m1 이상 환경인 경우



// 2. 실행 방법

// 2-1. actions 특정 job 지정 실행
act -j &quot;act -l 의 job name&quot; --secret-file local.secrets -s GITHUB_TOKEN=&quot;$(gh auth token)&quot;


// 2-2. 특정한 workflow만 실행하기
act -j lint -W .github/workflows/test.yml&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;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742103</guid>
      <comments>https://sojw.tistory.com/1169742103#entry1169742103comment</comments>
      <pubDate>Sat, 19 Aug 2023 00:25:55 +0900</pubDate>
    </item>
    <item>
      <title>slack webhook URL test</title>
      <link>https://sojw.tistory.com/1169742102</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;slack을 통해서 여러가지 알림들을 받는게 기본이 된 시대.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의식적으로 채널에 알림연동을 하고, 실제 workin의 결과를 통해서 연동이 잘 되어 있음을 확인 하곤 했었다.&lt;br /&gt;그러다, 최근 실제 working이 되기 전에 어떻게 Test 할 수 있나 라는 뒤늦은 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서. 기록으로 남겨둔다...&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;slack-webhook-URL-test&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1&quot;&gt;slack webhook URL test&lt;/h1&gt;
&lt;pre id=&quot;code_1692371748217&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;POST https://hooks.slack.com/services/xxxxxx
Content-type: application/json
{
    &quot;text&quot;: &quot;Hello, world.&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;curl&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;135&quot; data-ke-size=&quot;size26&quot;&gt;curl&lt;/h2&gt;
&lt;pre id=&quot;code_1692371786391&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl --request POST \
  --url https://hooks.slack.com/services/xxxxxx \
  --header 'Content-type: application/json' \
  --data '{&quot;text&quot;:&quot;Hello, world.&quot;}'&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;httpie&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;296&quot; data-ke-size=&quot;size26&quot;&gt;httpie&lt;/h2&gt;
&lt;pre id=&quot;code_1692371798708&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// style1
echo '{&quot;text&quot;:&quot;Hello, world.&quot;}' |  \
http POST https://hooks.slack.com/services/xxxxxx \
Content-type:application/json

// style2
http --json -v POST https://hooks.slack.com/services/xxxxxx  &quot;text&quot;=&quot;Hello, world.&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;</description>
      <category>emotional developer/detect-Web</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742102</guid>
      <comments>https://sojw.tistory.com/1169742102#entry1169742102comment</comments>
      <pubDate>Sat, 19 Aug 2023 00:16:54 +0900</pubDate>
    </item>
    <item>
      <title>Spring Actuator Health Probe</title>
      <link>https://sojw.tistory.com/1169742101</link>
      <description>&lt;h2 id=&quot;What&amp;rsquo;s-Kubernetes-Probe&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;What&amp;rsquo;s Kubernetes Probe&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;div style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-layout=&quot;default&quot;&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-number-column=&quot;false&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;h3 id=&quot;Probe&quot; style=&quot;color: #000000;&quot; data-renderer-start-pos=&quot;31&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Probe&lt;/b&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;livenessProbe&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;livenessProbe를 통과하지 못하면,&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/&quot; data-testid=&quot;link-with-safety&quot; data-renderer-mark=&quot;true&quot;&gt;&lt;u data-renderer-mark=&quot;true&quot;&gt;kubelet&lt;/u&gt;&lt;/a&gt;은 container를 종료하고, 해당 container는&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy&quot; data-testid=&quot;link-with-safety&quot; data-renderer-mark=&quot;true&quot;&gt;&lt;u data-renderer-mark=&quot;true&quot;&gt;재시작 정책&lt;/u&gt;&lt;/a&gt;의 대상이 됩니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;readinessProbe&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;readinessProbe를 통과하지 못하면, endpoint controller는 pod와 연관된 모든 서비스의 endpoint에서 pod의 IP 주소를 제거합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;startupProbe&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;startupProbe가 시작되면 startupProbe를 통과하기 전까지 다른 Probe는 활성화되지 않습니다.&lt;br /&gt;만약 startupProbe를 통과하지 못하면 kubelet은 container를 종료하고 해당 container는 재시작 정책의 대상이 됩니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;435&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;Pod-Lifecycle&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;437&quot; data-ke-size=&quot;size26&quot;&gt;Pod Lifecycle&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;https://loft.sh/blog/kubernetes-probes-startup-liveness-readiness/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://loft.sh/blog/kubernetes-probes-startup-liveness-readiness/&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;startupProbe&lt;/b&gt;에서 container상태를 확인하고, &lt;b&gt;livenessProbe&lt;/b&gt;와 &lt;b&gt;readinessProbe&lt;/b&gt;에서 container상태를 최종 확인하며 pod상태 결정
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 과정이 완료되기 전까지 network traffic을 차단&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정상적으로 pod구동 된 이후,
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;livenessProbe&lt;/b&gt; : 상태를 check 하고, pod을 재시작 할지 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;readinessProbe&lt;/b&gt; : pod에 traffic을 보낼지 결정&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;1715&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/teH3P/btspmVtSGid/lzQiz2Ce41gfYXhOzTWOKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/teH3P/btspmVtSGid/lzQiz2Ce41gfYXhOzTWOKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/teH3P/btspmVtSGid/lzQiz2Ce41gfYXhOzTWOKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FteH3P%2FbtspmVtSGid%2FlzQiz2Ce41gfYXhOzTWOKK%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;1040&quot; height=&quot;1715&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;1715&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nAWqQ/btsplbROrMu/G1FVYZDMUwJTWtsA6VdIbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nAWqQ/btsplbROrMu/G1FVYZDMUwJTWtsA6VdIbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nAWqQ/btsplbROrMu/G1FVYZDMUwJTWtsA6VdIbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnAWqQ%2FbtsplbROrMu%2FG1FVYZDMUwJTWtsA6VdIbk%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;710&quot; height=&quot;247&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;247&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8IBw9/btspFLiVIOn/smR4AIZhsG6QXZhWhszHU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8IBw9/btspFLiVIOn/smR4AIZhsG6QXZhWhszHU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8IBw9/btspFLiVIOn/smR4AIZhsG6QXZhWhszHU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8IBw9%2FbtspFLiVIOn%2FsmR4AIZhsG6QXZhWhszHU0%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;880&quot; height=&quot;460&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;460&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 id=&quot;HowTo&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;760&quot; data-ke-size=&quot;size26&quot;&gt;HowTo&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h2 id=&quot;Spring-Framework&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;767&quot; data-ke-size=&quot;size26&quot;&gt;Spring Framework&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;a href=&quot;https://www.baeldung.com/spring-liveness-readiness-probes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/spring-liveness-readiness-probes&lt;/a&gt;&lt;span data-testid=&quot;hover-card-trigger-wrapper&quot;&gt;&lt;span data-testid=&quot;inline-card-icon-and-title&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Spring Actuator
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Liveness : /actuator/health/liveness&lt;/li&gt;
&lt;li&gt;Readiness : /actuator/health/readiness&lt;/li&gt;
&lt;li&gt;custom status
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;3&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/spring-liveness-readiness-probes#1-updating-the-availability-state&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/spring-liveness-readiness-probes#1-updating-the-availability-state&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AvailabilityChangeEvent 를 통해, 각 probe의 상태를 변경 할 수 있다&lt;/li&gt;
&lt;li&gt;서비스의 특정한 상황에 따른 상태변경 요청이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&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;</description>
      <category>emotional developer/detect-Web</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742101</guid>
      <comments>https://sojw.tistory.com/1169742101#entry1169742101comment</comments>
      <pubDate>Mon, 31 Jul 2023 15:56:06 +0900</pubDate>
    </item>
    <item>
      <title>Git config - 사용자 정보 설정</title>
      <link>https://sojw.tistory.com/1169742100</link>
      <description>&lt;h3 id=&quot;현재-설정-정보-확인&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;현재 설정 정보 확인&lt;/h3&gt;
&lt;div style=&quot;background-color: #282a36; color: #f8f8f2;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;➜ ~ git config --list&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;credential.helper=osxkeychain&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;init.defaultbranch=main&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;user.name=블라블라(GP Kim) / Tech&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;user.email=gp.kim@&lt;/span&gt;&lt;span style=&quot;color: #8be9fd;&quot;&gt;sang.com&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;core.excludesfile=/Users/axxxxxxx/.gitignore_global&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;difftool.sourcetree.cmd=opendiff &quot;&lt;/span&gt;&lt;span style=&quot;color: #50fa7b;&quot;&gt;$LOCAL&quot; &quot;$&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;REMOTE&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;difftool.sourcetree.path=&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;mergetool.sourcetree.cmd=/Applications/Sourcetree.app/Contents/Resources/opendiff-w.sh &quot;&lt;/span&gt;&lt;span style=&quot;color: #50fa7b;&quot;&gt;$LOCAL&quot; &quot;$&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;REMOTE&quot; -ancestor &quot;&lt;/span&gt;&lt;span style=&quot;color: #50fa7b;&quot;&gt;$BASE&quot; -merge &quot;$&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;MERGED&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;mergetool.sourcetree.trustexitcode=true&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;commit.template=/Users/axxxxxxx/.stCommitMsg&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;filter.lfs.process=git-lfs filter-process&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;filter.lfs.required=true&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;filter.lfs.clean=git-lfs clean -- %f&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;filter.lfs.smudge=git-lfs smudge -- %f&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;사용자-정보-변경&quot; style=&quot;color: #000000;&quot; data-renderer-start-pos=&quot;665&quot; data-ke-size=&quot;size23&quot;&gt;사용자 정보 변경&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div style=&quot;background-color: #282a36; color: #f8f8f2;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt; git config --global user.name &quot;John Doe&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt; git config --global user.email johndoe@&lt;/span&gt;&lt;span style=&quot;color: #8be9fd;&quot;&gt;example.com&lt;/span&gt;&lt;/div&gt;
&lt;/div&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://git-scm.com/book/ko/v2/Git%EB%A7%9E%EC%B6%A4-Git-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고&lt;/a&gt;&lt;/p&gt;</description>
      <category>emotional developer</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742100</guid>
      <comments>https://sojw.tistory.com/1169742100#entry1169742100comment</comments>
      <pubDate>Fri, 21 Jul 2023 23:19:23 +0900</pubDate>
    </item>
    <item>
      <title>Synchronous, Asynchronous, Blocking, Non-Blocking</title>
      <link>https://sojw.tistory.com/1169742099</link>
      <description>&lt;h2 id=&quot;synchronous-vs-asynchronous&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Synchronous vs Asynchronous&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동기와 비동기를 구준하는 주요 기준은 작업순서의 보장 여부&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;synchronous%EB%8F%99%EA%B8%B0%ED%99%94&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Synchronous(동기화)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업의 순서가 보장됨. Thread는 요청한 작업의 결과를 받고 다음 작업 진행&lt;/li&gt;
&lt;li&gt;특정 API의 응답 반환 시간이 n분 소요 된다고 하면 이 요청이 실행 되는 n분 동안 Process/Thread는 다른 작업을 하지 못하고, 응답이 반환 되기를 기다려야 한다.&lt;/li&gt;
&lt;li&gt;장점 : 설계가 간단하고 직관적이다.&lt;/li&gt;
&lt;li&gt;단점 : 요청에 대한 결과가 반환되기 전까지 대기해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;asynchronous%EB%B9%84%EB%8F%99%EA%B8%B0%ED%99%94&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Asynchronous(비동기화)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업의 순서가 보장 되지 않음. Thread는 요청한 작업의 결과를 받지 않고 다음 작업 진행&lt;/li&gt;
&lt;li&gt;특정 API를 실행 하는데 시간이 n분 소요 되어도 그 시간동안 다른 작업을 수행할 수 있다.&lt;/li&gt;
&lt;li&gt;장점 : 요청에 대한 결과가 반환되기 전에 다른 작업을 수행할 수 있어서 자원을 효율적으로 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;단점 : 동기 방식보다 설계가 복잡하고, 논증적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;asynchronous-%EA%B5%AC%ED%98%84-%EB%B0%A9%EC%8B%9D&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Asynchronous 구현 방식&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Thread : 기본 구현 방식&lt;/li&gt;
&lt;li&gt;Future : 요청 작업 비동기로 결과 반환&lt;/li&gt;
&lt;li&gt;Completable Future : 의존성 있는 비동기 작업 처리&lt;/li&gt;
&lt;li&gt;Spring Async Task : Spring Async Threadpool 내에서 Thread 처리&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;blocking-vs-non-blocking&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Blocking vs Non-Blocking&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;블럭킹과 논블럭킹을 구분하는 주요기준은 제어권의 양도 시점&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;blocking&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Blocking&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 함수(A)가 다른 함수(B)를 호출할 때, 호출한 함수(B)에게 제어권을 양도 &amp;rarr; 함수 A는 제어권을 상실함으로써 일시적으로 작업을 멈춤&lt;/li&gt;
&lt;li&gt;Process는 요청한 작업이 종료 될 때 까지 waiting&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;non-blocking&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Non-Blocking&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 함수(A)가 다른 함수(B)를 호출할 때, 호출한 함수(B)에게 제어권을 양도 하지 않음&lt;/li&gt;
&lt;li&gt;Process는 요청한 작업이 끝나지 않더 라도 작업을 진행 할 수 있음&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>emotional developer/detect-Web</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742099</guid>
      <comments>https://sojw.tistory.com/1169742099#entry1169742099comment</comments>
      <pubDate>Tue, 4 Jul 2023 01:13:21 +0900</pubDate>
    </item>
    <item>
      <title>6-Caching Strategies to Remember while designing Cache System</title>
      <link>https://sojw.tistory.com/1169742098</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://javascript.plainenglish.io/6-caching-strategies-to-remember-while-designing-cache-system-da058a3757cf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://javascript.plainenglish.io/6-caching-strategies-to-remember-while-designing-cache-system-da058a3757cf&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686933544172&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;6-Caching Strategies to Remember while designing Cache System&quot; data-og-description=&quot;How to invalidate the cache, strategies around Read v/s Write Cache,Ways to invalidate the Cache, terminologies around Cache System &amp;amp; Much&amp;hellip;&quot; data-og-host=&quot;javascript.plainenglish.io&quot; data-og-source-url=&quot;https://javascript.plainenglish.io/6-caching-strategies-to-remember-while-designing-cache-system-da058a3757cf&quot; data-og-url=&quot;https://javascript.plainenglish.io/6-caching-strategies-to-remember-while-designing-cache-system-da058a3757cf&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eBWUt/hyS1cS9lKM/K9icVwtXU2U7QtiEDKSbdK/img.png?width=1200&amp;amp;height=375&amp;amp;face=0_0_1200_375&quot;&gt;&lt;a href=&quot;https://javascript.plainenglish.io/6-caching-strategies-to-remember-while-designing-cache-system-da058a3757cf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://javascript.plainenglish.io/6-caching-strategies-to-remember-while-designing-cache-system-da058a3757cf&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eBWUt/hyS1cS9lKM/K9icVwtXU2U7QtiEDKSbdK/img.png?width=1200&amp;amp;height=375&amp;amp;face=0_0_1200_375');&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;6-Caching Strategies to Remember while designing Cache System&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;How to invalidate the cache, strategies around Read v/s Write Cache,Ways to invalidate the Cache, terminologies around Cache System &amp;amp; Much&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;javascript.plainenglish.io&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #292c32; text-align: start;&quot;&gt;캐시 시스템의 주요 성능 지표&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;캐시 적중률: 이 메트릭은 요청된 항목이 캐시에서 발견된 횟수의 비율을 측정합니다. 캐시 적중률이 높을수록 캐시에서 더 많은 데이터가 제공되어 외부 저장소에 액세스할 필요성이 줄어들고 성능이 향상됩니다.&lt;/li&gt;
&lt;li&gt;지연 시간: 지연 시간은 데이터에 액세스하는 데 걸리는 시간을 의미합니다. 캐싱 시스템에서 지연 시간이 짧다는 것은 데이터가 더 빨리 제공되어 전반적인 성능이 향상된다는 것을 의미합니다.&lt;/li&gt;
&lt;li&gt;처리량: 처리량은 주어진 시간 프레임에서 처리할 수 있는 데이터의 양을 측정합니다. 처리량이 높은 캐싱 시스템은 더 많은 요청을 처리하고 더 많은 데이터를 제공할 수 있으므로 전반적인 성능이 향상됩니다.&lt;/li&gt;
&lt;li&gt;캐시 크기: 캐시 크기는 캐시에 할당된 메모리 또는 스토리지의 양입니다. 캐시 크기는 캐시의 적중률과 누락률에 영향을 줄 수 있습니다. 캐시 크기가 클수록 적중률이 높아질 수 있지만 캐싱 솔루션의 비용과 복잡성이 증가할 수 있습니다.&lt;/li&gt;
&lt;li&gt;캐시&amp;nbsp;미스&amp;nbsp;비율:&amp;nbsp;이&amp;nbsp;지표는&amp;nbsp;요청된&amp;nbsp;항목이&amp;nbsp;캐시에서&amp;nbsp;발견되지&amp;nbsp;않아&amp;nbsp;외부&amp;nbsp;저장소에서&amp;nbsp;가져와야&amp;nbsp;하는&amp;nbsp;횟수의&amp;nbsp;비율을&amp;nbsp;측정합니다.&amp;nbsp;캐시&amp;nbsp;누락률이&amp;nbsp;높다는&amp;nbsp;것은&amp;nbsp;외부&amp;nbsp;스토리지에서&amp;nbsp;더&amp;nbsp;많은&amp;nbsp;데이터를&amp;nbsp;가져와&amp;nbsp;성능이&amp;nbsp;저하된다는&amp;nbsp;것을&amp;nbsp;의미합니다.&lt;/li&gt;
&lt;/ol&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #292c32; text-align: start;&quot;&gt;캐시 무효화 방법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;시간 기반 무효화(TTL): 이 전략에서는 일정 시간이 지나면 캐시에 있는 데이터가 무효화됩니다. 이는 구현하기 쉬운 간단하고 효과적인 전략입니다. &lt;span style=&quot;color: #252525; text-align: start;&quot;&gt;그러나 일부 데이터는 다른 데이터보다 빠르게 오래될 수 있으므로 모든 사용 사례에 적합하지 않을 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;이벤트 기반 무효화: 이 전략에서는 기본 데이터 소스 변경 또는 기타 관련 이벤트와 같이 발생하는 특정 이벤트에 따라 캐시의 데이터가 무효화됩니다. 이는 필요한 경우에만 데이터가 무효화되도록 하는 보다 타깃화된 무효화 접근 방식입니다. 하지만 애플리케이션 및 기초 데이터 소스와의 향상된 통합이 필요합니다.&lt;/li&gt;
&lt;li&gt;버전 기반 무효화: 이 전략에서는 캐시에 있는 각 데이터에 데이터가 변경될 때마다 증가하는 버전 번호가 할당됩니다. 데이터가 무효화되면 캐시에서 버전 번호가 업데이트되어 가장 최신 버전의 데이터만 사용되도록 합니다. 이 전략은 자주 변경되는 데이터에 효과적일 수 있지만 버전 번호를 관리하는 데 추가적인 오버헤드가 필요합니다.&lt;/li&gt;
&lt;li&gt;가장 최근에 사용된(LRU) 무효화: 이 전략에서는 캐시가 용량 제한에 도달하면 캐시에서 가장 최근에 사용된 데이터가 무효화됩니다. 이렇게 하면 가장 자주 사용되는 데이터가 캐시에 남아 오래된 데이터를 저장할 위험이 줄어듭니다. 그러나 일부 데이터는 자주 액세스하지 않지만 여전히 캐시에 저장해야 할 수 있으므로 모든 사용 사례에 적합하지 않을 수 있습니다.&lt;/li&gt;
&lt;li&gt;수동 무효화: 이 전략에서는 애플리케이션 또는 관리자가 수동으로 무효화를 트리거합니다. 이 방법은 캐시에 대한 유연성과 제어가 가장 뛰어나지만 무효화 프로세스를 관리하는 데 더 많은 오버헤드가 필요합니다. 여기에는&amp;nbsp;퍼지,&amp;nbsp;금지,&amp;nbsp;새로&amp;nbsp;고침과&amp;nbsp;같은&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;방법이&amp;nbsp;포함됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742098</guid>
      <comments>https://sojw.tistory.com/1169742098#entry1169742098comment</comments>
      <pubDate>Sat, 17 Jun 2023 01:50:43 +0900</pubDate>
    </item>
    <item>
      <title>Five API Performance Optimization Tricks that Every Java Developer Must Know</title>
      <link>https://sojw.tistory.com/1169742097</link>
      <description>&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://medium.com/javarevisited/five-api-performance-optimization-tricks-that-every-java-developer-must-know-75324ee1d244&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/javarevisited/five-api-performance-optimization-tricks-that-every-java-developer-must-know-75324ee1d244&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686367614241&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;Five API Performance Optimization Tricks that Every Java Developer Must Know&quot; data-og-description=&quot;Why is your API response so slow? Maybe you need to solve these problems.&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/javarevisited/five-api-performance-optimization-tricks-that-every-java-developer-must-know-75324ee1d244&quot; data-og-url=&quot;https://medium.com/javarevisited/five-api-performance-optimization-tricks-that-every-java-developer-must-know-75324ee1d244&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XvtHx/hySVJ52RnO/vpd9MnGALD0Llf93xRNj3K/img.jpg?width=1200&amp;amp;height=801&amp;amp;face=0_0_1200_801&quot;&gt;&lt;a href=&quot;https://medium.com/javarevisited/five-api-performance-optimization-tricks-that-every-java-developer-must-know-75324ee1d244&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/javarevisited/five-api-performance-optimization-tricks-that-every-java-developer-must-know-75324ee1d244&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XvtHx/hySVJ52RnO/vpd9MnGALD0Llf93xRNj3K/img.jpg?width=1200&amp;amp;height=801&amp;amp;face=0_0_1200_801');&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;Five API Performance Optimization Tricks that Every Java Developer Must Know&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Why is your API response so slow? Maybe you need to solve these problems.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;h3 data-ke-size=&quot;size23&quot;&gt;Five Tricks&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;de22&quot;&gt;Parallel call&lt;/li&gt;
&lt;li&gt;Avoid large transaction&lt;/li&gt;
&lt;li&gt;Add appropriate index&lt;/li&gt;
&lt;li&gt;Return fewer data&lt;/li&gt;
&lt;li&gt;Use cache&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;f3e3&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;Finally&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292c32; text-align: start;&quot;&gt;여기에 5가지 일반적인 API 성능 최적화 요령을 나열했습니다. 이러한 트릭은 &lt;b&gt;시스템에 특정 동시 접속자가 몰리는 경우에만 효과적&lt;/b&gt;입니다. &lt;b&gt;시스템 액세스가 많지 않은 경우에는 위의 제안을 신중하게 고려&lt;/b&gt;하시기 바랍니다. 보다 효과적인 다른 솔루션을 찾아보시기 바랍니다.&lt;/span&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742097</guid>
      <comments>https://sojw.tistory.com/1169742097#entry1169742097comment</comments>
      <pubDate>Sat, 10 Jun 2023 12:29:10 +0900</pubDate>
    </item>
    <item>
      <title>Databases: An Overview - MongoDB</title>
      <link>https://sojw.tistory.com/1169742096</link>
      <description>&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://towardsdatascience.com/databases-an-overview-97c54628b824&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://towardsdatascience.com/databases-an-overview-97c54628b824&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686284075880&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;Databases: An Overview&quot; data-og-description=&quot;Part 2: Underlying Architecture of Distributed File Systems of MongoDB and HBase and Database Operations in Python&quot; data-og-host=&quot;towardsdatascience.com&quot; data-og-source-url=&quot;https://towardsdatascience.com/databases-an-overview-97c54628b824&quot; data-og-url=&quot;https://towardsdatascience.com/databases-an-overview-97c54628b824&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/btEbBB/hySVFhKRt1/47anW2zIDJeqsahOw1tn7K/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800&quot;&gt;&lt;a href=&quot;https://towardsdatascience.com/databases-an-overview-97c54628b824&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://towardsdatascience.com/databases-an-overview-97c54628b824&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/btEbBB/hySVFhKRt1/47anW2zIDJeqsahOw1tn7K/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800');&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;Databases: An Overview&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Part 2: Underlying Architecture of Distributed File Systems of MongoDB and HBase and Database Operations in Python&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;towardsdatascience.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;h2 id=&quot;33ab&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;MongoDB&lt;/h2&gt;
&lt;p id=&quot;b244&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;MongoDB is a document-based NoSQL database. It requires no fixed schema definition. Mongo DB stores data as Binary JSON or BSON. It supports horizontal scaling. Several servers instance group together as a cluster to support Mongo DB as a distributed system.&lt;/p&gt;
&lt;p id=&quot;0f72&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;MongoDB uses MongoDB query language and supports Adhoc queries, Replication, and Sharding. Sharding is a feature of MongoDB that helps it to operate as a distributed data system. Let&amp;rsquo;s look at how MongoDB implements these features.&lt;/p&gt;
&lt;p id=&quot;e4dd&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Replication in Mongo&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;5ab7&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Replication serves as a very important feature in order to protect data loss from one server, increase the availability of data, and give protection from failures.&lt;/p&gt;
&lt;p id=&quot;bc73&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;MongoDB achieves replication using the concept replica sets. A replica set is a group of mongod instances that host the same data set. One of the nodes is selected as the primary or main node. This is called the primary node. All others are called secondary nodes. The primary node receives all the operations from the user and the secondaries are updated from the primary one by using the same operation to maintain consistency. If the primary node goes down, one of the secondary nodes is selected as the primary node and the operations are carried forward. When the fallen node recovers, it joins the cluster as the secondary nodes. We can control our cluster of mongo instances using&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Mongo Atlas.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;Mongo clusters are created based on the idea of horizontal scaling and adding of instances.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;527&quot; data-origin-height=&quot;421&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ensEl1/btsje1sL2KR/24YctBfYVfxltaZ1udsuVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ensEl1/btsje1sL2KR/24YctBfYVfxltaZ1udsuVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ensEl1/btsje1sL2KR/24YctBfYVfxltaZ1udsuVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FensEl1%2Fbtsje1sL2KR%2F24YctBfYVfxltaZ1udsuVK%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;527&quot; height=&quot;421&quot; data-origin-width=&quot;527&quot; data-origin-height=&quot;421&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Replica set schematic: Image by Author&lt;/p&gt;
&lt;p id=&quot;f9e7&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Sharding in Mongo DB&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;3c6e&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Sharding is used by MongoDB to store data across multiple machines. It uses horizontal scaling to add more machines to distribute data and operation with respect to the growth of load and demand.&lt;/p&gt;
&lt;p id=&quot;2f99&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Sharding arrangement in MongoDB has mainly three components:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li id=&quot;73ec&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;b&gt;Shards or replica sets:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;Each shard serves as a separate replica set. They store all the data. They target to increase the consistency and availability of the data.&lt;/li&gt;
&lt;li id=&quot;fdec&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;b&gt;Configuration Servers:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;They are like the managers of the clusters. These servers contain the cluster's metadata. They actually have the mapping of the cluster's data to the shards. When a query comes, query routers use these mappings from the config servers to target the required shard.&lt;/li&gt;
&lt;li id=&quot;b98f&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;b&gt;Query Router:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;The query router is mongo instances which serve as interfaces for user applications. They take in the user queries from the applications and serve the applications with the required results. Usually, there are multiple query router per cluster for load distribution.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;621&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7FIM6/btsjimbZHOa/oicHJm3RKLoyXaSxRvDzwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7FIM6/btsjimbZHOa/oicHJm3RKLoyXaSxRvDzwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7FIM6/btsjimbZHOa/oicHJm3RKLoyXaSxRvDzwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7FIM6%2FbtsjimbZHOa%2FoicHJm3RKLoyXaSxRvDzwK%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;700&quot; height=&quot;620&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;621&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image by author&lt;/p&gt;
&lt;p id=&quot;110a&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;The above image shows the sharding arrangement for MongoDB. Though the image has only 2 query servers and shards, generally there are more in an actual cluster, though by default case there are 3 config servers in a cluster.&lt;/p&gt;
&lt;p id=&quot;087a&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;The ideas we talked about above are the two most important ideas behind MongoDB operations and its distributed data system architecture.&lt;/p&gt;
&lt;p id=&quot;152a&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Now, let&amp;rsquo;s take a look at how Apache HBase implements the ideas of distributed systems.&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>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742096</guid>
      <comments>https://sojw.tistory.com/1169742096#entry1169742096comment</comments>
      <pubDate>Fri, 9 Jun 2023 13:14:59 +0900</pubDate>
    </item>
    <item>
      <title>Docker Architecture</title>
      <link>https://sojw.tistory.com/1169742095</link>
      <description>&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://medium.com/@basecs101/understanding-docker-architecture-latest-c7a165571d89&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@basecs101/understanding-docker-architecture-latest-c7a165571d89&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686283909524&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;Understanding Docker Architecture&quot; data-og-description=&quot;Know the docker design and its complete working mechanism&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@basecs101/understanding-docker-architecture-latest-c7a165571d89&quot; data-og-url=&quot;https://medium.com/@basecs101/understanding-docker-architecture-latest-c7a165571d89&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ku7ao/hySWpFaHJ8/0hbWJxtEqKLCADHGw2BpS0/img.png?width=1200&amp;amp;height=601&amp;amp;face=0_0_1200_601&quot;&gt;&lt;a href=&quot;https://medium.com/@basecs101/understanding-docker-architecture-latest-c7a165571d89&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@basecs101/understanding-docker-architecture-latest-c7a165571d89&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ku7ao/hySWpFaHJ8/0hbWJxtEqKLCADHGw2BpS0/img.png?width=1200&amp;amp;height=601&amp;amp;face=0_0_1200_601');&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;Understanding Docker Architecture&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Know the docker design and its complete working mechanism&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;701&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOM4Xt/btsjcVmflY5/qmxyqLeTeRff6GiULnKq71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOM4Xt/btsjcVmflY5/qmxyqLeTeRff6GiULnKq71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOM4Xt/btsjcVmflY5/qmxyqLeTeRff6GiULnKq71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOM4Xt%2FbtsjcVmflY5%2FqmxyqLeTeRff6GiULnKq71%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;1400&quot; height=&quot;701&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;701&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@koo8624/Docker-%EB%B2%88%EC%97%AD-%EB%8F%84%EC%BB%A4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-Docker-Architecture-Overview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@koo8624/Docker-%EB%B2%88%EC%97%AD-%EB%8F%84%EC%BB%A4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-Docker-Architecture-Overview&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.leafcats.com/146&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.leafcats.com/146&lt;/a&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742095</guid>
      <comments>https://sojw.tistory.com/1169742095#entry1169742095comment</comments>
      <pubDate>Fri, 9 Jun 2023 13:12:55 +0900</pubDate>
    </item>
    <item>
      <title>The Architecture of Prometheus</title>
      <link>https://sojw.tistory.com/1169742094</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://prometheus.io/docs/introduction/overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://prometheus.io/docs/introduction/overview/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686283719551&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;Overview | Prometheus&quot; data-og-description=&quot;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&quot; data-og-host=&quot;prometheus.io&quot; data-og-source-url=&quot;https://prometheus.io/docs/introduction/overview/&quot; data-og-url=&quot;https://prometheus.io/docs/introduction/overview/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/je4sD/hySVFa0gBI/wYdUYWx1ncK5Zvfm3pE3l0/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192,https://scrap.kakaocdn.net/dn/LkdbO/hySWpFazbv/RdooQUKhuMLcGhfiY70Gx0/img.png?width=1351&amp;amp;height=811&amp;amp;face=0_0_1351_811&quot;&gt;&lt;a href=&quot;https://prometheus.io/docs/introduction/overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://prometheus.io/docs/introduction/overview/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/je4sD/hySVFa0gBI/wYdUYWx1ncK5Zvfm3pE3l0/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192,https://scrap.kakaocdn.net/dn/LkdbO/hySWpFazbv/RdooQUKhuMLcGhfiY70Gx0/img.png?width=1351&amp;amp;height=811&amp;amp;face=0_0_1351_811');&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;Overview | Prometheus&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;prometheus.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIikIM/btsjaLxO2OA/tQSoZZptFAQb3De8KaKDKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIikIM/btsjaLxO2OA/tQSoZZptFAQb3De8KaKDKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIikIM/btsjaLxO2OA/tQSoZZptFAQb3De8KaKDKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIikIM%2FbtsjaLxO2OA%2FtQSoZZptFAQb3De8KaKDKk%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;1280&quot; height=&quot;768&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;768&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://badcandy.github.io/2018/12/25/prometheus-architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://badcandy.github.io/2018/12/25/prometheus-architecture/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686283761615&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;Prometheus #1 - 아키텍쳐와 개념&quot; data-og-description=&quot;Prometheus #1 - 아키텍쳐와 개념 Dec 25, 2018 What is Prometheus? 메트릭 정보를 수집하여 시스템을 모니터링하고 Alerting을 지원하는 오픈소스 Architecture Concept Data Model Metric name 측정되는 시스템의 기능 ex) &quot; data-og-host=&quot;badcandy.github.io&quot; data-og-source-url=&quot;https://badcandy.github.io/2018/12/25/prometheus-architecture/&quot; data-og-url=&quot;https://badcandy.github.io/2018/12/25/prometheus-architecture/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bZbYfN/hySWp6dWgB/8eFmvaeo54MClMjLhd6uAk/img.png?width=1354&amp;amp;height=798&amp;amp;face=0_0_1354_798&quot;&gt;&lt;a href=&quot;https://badcandy.github.io/2018/12/25/prometheus-architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://badcandy.github.io/2018/12/25/prometheus-architecture/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bZbYfN/hySWp6dWgB/8eFmvaeo54MClMjLhd6uAk/img.png?width=1354&amp;amp;height=798&amp;amp;face=0_0_1354_798');&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;Prometheus #1 - 아키텍쳐와 개념&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Prometheus #1 - 아키텍쳐와 개념 Dec 25, 2018 What is Prometheus? 메트릭 정보를 수집하여 시스템을 모니터링하고 Alerting을 지원하는 오픈소스 Architecture Concept Data Model Metric name 측정되는 시스템의 기능 ex)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;badcandy.github.io&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;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>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742094</guid>
      <comments>https://sojw.tistory.com/1169742094#entry1169742094comment</comments>
      <pubDate>Fri, 9 Jun 2023 13:09:36 +0900</pubDate>
    </item>
    <item>
      <title>5 ways to review code without wasting everyone&amp;rsquo;s time</title>
      <link>https://sojw.tistory.com/1169742093</link>
      <description>&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://medium.com/volvo-cars-engineering/5-ways-to-review-code-without-wasting-everyones-time-aedeecc51094&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/volvo-cars-engineering/5-ways-to-review-code-without-wasting-everyones-time-aedeecc51094&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686283434263&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;5 ways to review code without wasting everyone&amp;rsquo;s time&quot; data-og-description=&quot;The what and how to review pull requests&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/volvo-cars-engineering/5-ways-to-review-code-without-wasting-everyones-time-aedeecc51094&quot; data-og-url=&quot;https://medium.com/volvo-cars-engineering/5-ways-to-review-code-without-wasting-everyones-time-aedeecc51094&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cPOC9L/hySVLI4iWz/W9xtv1UgsakkWRaTVM3SfK/img.png?width=1200&amp;amp;height=269&amp;amp;face=0_0_1200_269&quot;&gt;&lt;a href=&quot;https://medium.com/volvo-cars-engineering/5-ways-to-review-code-without-wasting-everyones-time-aedeecc51094&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/volvo-cars-engineering/5-ways-to-review-code-without-wasting-everyones-time-aedeecc51094&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cPOC9L/hySVLI4iWz/W9xtv1UgsakkWRaTVM3SfK/img.png?width=1200&amp;amp;height=269&amp;amp;face=0_0_1200_269');&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;5 ways to review code without wasting everyone&amp;rsquo;s time&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The what and how to review pull requests&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292c32; text-align: start;&quot;&gt;요약&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 다음에 코드를 검토할 때 기억했으면 하는 핵심 사항의 목록입니다:&lt;span style=&quot;background-color: #ffffff; color: #292c32; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음은 다음에 코드를 검토할 때 기억했으면 하는 핵심 사항의 목록입니다:&lt;/li&gt;
&lt;li&gt;합의 사항을 확인합니다(예: 단위 테스트가 있는가? 문서가 있는가?).&lt;/li&gt;
&lt;li&gt;다른 시각을 제공하세요(예: 오타 확인, 혼동되는 부분 식별).&lt;/li&gt;
&lt;li&gt;이해가 안 되는 부분이 있으면 질문하고 변경하고 싶은 부분이 있으면 피드백을 제공하세요.&lt;/li&gt;
&lt;li&gt;풀 리퀘스트가 불분명하거나 검토할 수 없는 경우 거절하세요.&lt;/li&gt;
&lt;li&gt;댓글을 작성할 때 무례하게 행동하지 마세요.&lt;/li&gt;
&lt;/ul&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>emotional developer</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742093</guid>
      <comments>https://sojw.tistory.com/1169742093#entry1169742093comment</comments>
      <pubDate>Fri, 9 Jun 2023 13:05:29 +0900</pubDate>
    </item>
    <item>
      <title>Avoiding cache stampede at DoorDash</title>
      <link>https://sojw.tistory.com/1169742092</link>
      <description>&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://medium.com/@DoorDash/avoiding-cache-stampede-at-doordash-55bbf596d94b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@DoorDash/avoiding-cache-stampede-at-doordash-55bbf596d94b&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1685374352849&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;Avoiding cache stampede at DoorDash&quot; data-og-description=&quot;By Zohaib Sibte Hassan, Software Engineer at DoorDash&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@DoorDash/avoiding-cache-stampede-at-doordash-55bbf596d94b&quot; data-og-url=&quot;https://medium.com/@DoorDash/avoiding-cache-stampede-at-doordash-55bbf596d94b&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xcMg8/hySNkdGyrA/kDHJKHcVlBZqzDCYq38yG0/img.png?width=601&amp;amp;height=501&amp;amp;face=0_0_601_501&quot;&gt;&lt;a href=&quot;https://medium.com/@DoorDash/avoiding-cache-stampede-at-doordash-55bbf596d94b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@DoorDash/avoiding-cache-stampede-at-doordash-55bbf596d94b&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xcMg8/hySNkdGyrA/kDHJKHcVlBZqzDCYq38yG0/img.png?width=601&amp;amp;height=501&amp;amp;face=0_0_601_501');&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;Avoiding cache stampede at DoorDash&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;By Zohaib Sibte Hassan, Software Engineer at DoorDash&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;DoorDash Cache 전략.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;501&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/S09yk/btshBlAL4yc/Aa0kWvlLfObcGOkSw5GYZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/S09yk/btshBlAL4yc/Aa0kWvlLfObcGOkSw5GYZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/S09yk/btshBlAL4yc/Aa0kWvlLfObcGOkSw5GYZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FS09yk%2FbtshBlAL4yc%2FAa0kWvlLfObcGOkSw5GYZK%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;601&quot; height=&quot;501&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;501&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A typical caching setup&lt;/p&gt;
&lt;h1 id=&quot;799e&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;The debouncer approach&lt;/h1&gt;
&lt;p id=&quot;6d60&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;To solve the problem, we took inspiration from something front-end engineers use frequently.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Debouncing&lt;span&gt;&amp;nbsp;&lt;/span&gt;is a common practice in the JS world to prevent duplicate events from firing and causing noise in the system. A well-known way to create a debouncing function looks something like this (using lodash or underscore.js):&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;a href=&quot;https://github.com/syesildag/debounce/blob/master/src/main/java/debounce/DebounceExecutor.java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/syesildag/debounce/blob/master/src/main/java/debounce/DebounceExecutor.java&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1685375539840&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;GitHub - syesildag/debounce&quot; data-og-description=&quot;Contribute to syesildag/debounce development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/syesildag/debounce/blob/master/src/main/java/debounce/DebounceExecutor.java&quot; data-og-url=&quot;https://github.com/syesildag/debounce&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b4l1Gu/hySNa91pUA/I2kpH0t4yZ5BYGMod3TBE1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/syesildag/debounce/blob/master/src/main/java/debounce/DebounceExecutor.java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/syesildag/debounce/blob/master/src/main/java/debounce/DebounceExecutor.java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b4l1Gu/hySNa91pUA/I2kpH0t4yZ5BYGMod3TBE1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - syesildag/debounce&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to syesildag/debounce development by creating an account on GitHub.&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;pre id=&quot;code_1685375557179&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import java.lang.Thread;

public class DebounceExecutor
{
   private ScheduledExecutorService executor;
   private ScheduledFuture&amp;lt;Object&amp;gt; future;
   
   public DebounceExecutor()
   {
      this.executor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory()
      {
         @Override
         public Thread newThread(Runnable r)
         {
            Thread t = new Thread(r, &quot;Debouncer&quot;);
            t.setDaemon(true);
            return t;
         }
      });
   }
   
   public ScheduledFuture&amp;lt;Object&amp;gt; debounce(long delay, Callable&amp;lt;Object&amp;gt; task)
   {
      if (this.future != null &amp;amp;&amp;amp; !this.future.isDone())
         this.future.cancel(false);
      
      return this.future = this.executor.schedule(task, delay, TimeUnit.MILLISECONDS);
   }
}&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;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742092</guid>
      <comments>https://sojw.tistory.com/1169742092#entry1169742092comment</comments>
      <pubDate>Tue, 30 May 2023 00:33:21 +0900</pubDate>
    </item>
    <item>
      <title>System Design &amp;mdash; Scaling from Zero to Millions Of Users</title>
      <link>https://sojw.tistory.com/1169742091</link>
      <description>&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://medium.com/geekculture/system-design-scaling-from-zero-to-millions-of-users-deca270ef784&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/geekculture/system-design-scaling-from-zero-to-millions-of-users-deca270ef784&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1685373711995&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;System Design &amp;mdash; Scaling from Zero to Millions Of Users&quot; data-og-description=&quot;Note: I have read this great book System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu in depth. So most of my definitions and images&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/geekculture/system-design-scaling-from-zero-to-millions-of-users-deca270ef784&quot; data-og-url=&quot;https://medium.com/geekculture/system-design-scaling-from-zero-to-millions-of-users-deca270ef784&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ejnKIf/hySNcfEGFz/WNFcYzG8gN4qczxP8x2pdK/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800&quot;&gt;&lt;a href=&quot;https://medium.com/geekculture/system-design-scaling-from-zero-to-millions-of-users-deca270ef784&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/geekculture/system-design-scaling-from-zero-to-millions-of-users-deca270ef784&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ejnKIf/hySNcfEGFz/WNFcYzG8gN4qczxP8x2pdK/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800');&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;System Design &amp;mdash; Scaling from Zero to Millions Of Users&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Note: I have read this great book System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu in depth. So most of my definitions and images&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;h1 id=&quot;b5ac&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;b&gt;Load Balancer&lt;/b&gt;&lt;/h1&gt;
&lt;p id=&quot;2e26&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;A load balancer evenly distributes incoming traffic among web servers that are defined in a load-balanced set. The user connects to the public IP of the load balancer which further connects with the private IP of our defined servers.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1035&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eIKeoO/btshA0jaEvG/IuzPlh4Nfk2Td8AKKQonk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eIKeoO/btshA0jaEvG/IuzPlh4Nfk2Td8AKKQonk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eIKeoO/btshA0jaEvG/IuzPlh4Nfk2Td8AKKQonk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeIKeoO%2FbtshA0jaEvG%2FIuzPlh4Nfk2Td8AKKQonk0%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;700&quot; height=&quot;518&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1035&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image source&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://amzn.eu/d/hLN5N8v&quot;&gt;&lt;b&gt;System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu&lt;/b&gt;&lt;/a&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;To handle it we can follow the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Data Replication&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;strategy.&lt;/p&gt;
&lt;p id=&quot;eefa&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Wikipedia: &amp;ldquo;Database replication can be used in many database management systems, usually with a master/slave relationship between the original (master) and the copies (slaves)&amp;rdquo;.&lt;/p&gt;
&lt;p id=&quot;2498&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A master database generally only supports write operations. A slave database gets copies of the data from the master database and only supports read operations.&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;3816&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Most applications require a much higher ratio of reads to writes; thus, the number of slave databases in a system is usually larger than the number of master databases.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;1102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvReO0/btshE0bNrtW/qR0yx9MqTvf9jck66OB631/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvReO0/btshE0bNrtW/qR0yx9MqTvf9jck66OB631/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvReO0/btshE0bNrtW/qR0yx9MqTvf9jck66OB631/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvReO0%2FbtshE0bNrtW%2FqR0yx9MqTvf9jck66OB631%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;700&quot; height=&quot;641&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;1102&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image source&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://amzn.eu/d/hLN5N8v&quot;&gt;&lt;b&gt;System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu&lt;/b&gt;&lt;/a&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;After all the above discussions, our system design:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIeG0y/btshChrjNaC/xAcW9WsEB3SF6gE6vCvz6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIeG0y/btshChrjNaC/xAcW9WsEB3SF6gE6vCvz6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIeG0y/btshChrjNaC/xAcW9WsEB3SF6gE6vCvz6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIeG0y%2FbtshChrjNaC%2FxAcW9WsEB3SF6gE6vCvz6k%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;700&quot; height=&quot;675&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image source&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://amzn.eu/d/hLN5N8v&quot;&gt;&lt;b&gt;System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p id=&quot;3d2a&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Now, we have a basic understanding of the web and data tiers, it is time to&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;improve the load/response time.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;3e52&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Caching&lt;/b&gt;&lt;/h2&gt;
&lt;p id=&quot;b7f0&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;A cache is a temporary storage area that stores the result of expensive responses or frequently accessed data in memory so that subsequent requests are served more quickly. The application performance is greatly affected by calling the database repeatedly. The cache can help in solving this problem.&lt;/p&gt;
&lt;p id=&quot;9c63&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Once we get the request, the web server checks if the data is present in the cache. If it is present (also called cache-hit), then our cache access it and directly sends the data to the client. If data is not present in our cache (also called cache-miss), it queries the database then stores the response in the cache and sends data back to the client.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmXNaD/btshCfUAL5H/BT92KIEQJNxmIK2A2Q6YD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmXNaD/btshCfUAL5H/BT92KIEQJNxmIK2A2Q6YD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmXNaD/btshCfUAL5H/BT92KIEQJNxmIK2A2Q6YD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmXNaD%2FbtshCfUAL5H%2FBT92KIEQJNxmIK2A2Q6YD0%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;700&quot; height=&quot;123&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;244&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image source&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://amzn.eu/d/hLN5N8v&quot;&gt;&lt;b&gt;System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;e95a&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CDN&lt;/b&gt;&lt;/h2&gt;
&lt;p id=&quot;d4ef&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;A CDN is a network of geographically dispersed servers used to deliver static content. CDN servers cache static content like images, videos, CSS, JavaScript files, etc.&lt;/p&gt;
&lt;p id=&quot;26ac&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Note:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;There is also a concept of dynamic content caching which enables the caching of HTML pages that are based on request path, query strings, cookies, and request headers.&lt;/p&gt;
&lt;p id=&quot;f175&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Workflow of CDN:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5T3Py/btshWsY0fNy/L7iVQyWagPhay3x1gKWIUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5T3Py/btshWsY0fNy/L7iVQyWagPhay3x1gKWIUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5T3Py/btshWsY0fNy/L7iVQyWagPhay3x1gKWIUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5T3Py%2FbtshWsY0fNy%2FL7iVQyWagPhay3x1gKWIUk%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;700&quot; height=&quot;217&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image source&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://amzn.eu/d/hLN5N8v&quot;&gt;&lt;b&gt;System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu&lt;/b&gt;&lt;/a&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;Now let&amp;rsquo;s add cache and CDN to our existing system design:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1qICA/btshBiRqmoN/5ViDSBOrochVYR7354MBBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1qICA/btshBiRqmoN/5ViDSBOrochVYR7354MBBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1qICA/btshBiRqmoN/5ViDSBOrochVYR7354MBBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1qICA%2FbtshBiRqmoN%2F5ViDSBOrochVYR7354MBBk%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;700&quot; height=&quot;667&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1333&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image source&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://amzn.eu/d/hLN5N8v&quot;&gt;&lt;b&gt;System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;81e4&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;Database Scaling&lt;/h2&gt;
&lt;p id=&quot;82c2&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Database Scaling can also be done in 2 ways:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Vertical and Horizontal scaling&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;4930&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Vertical scaling&lt;/b&gt;, also known as scaling up, is the scaling by adding more power (CPU, RAM, DISK, etc.) to an existing machine. We can generally get highly powerful database servers say around 24 TB of RAM, these kinds of servers can store and handle lots and lots of data.&lt;/p&gt;
&lt;p id=&quot;781e&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;But it comes with few limitations: Restricted user base, higher risk of SPOF, and vertical scaling becomes highly expensive as you go higher to such powerful database servers.&lt;/p&gt;
&lt;p id=&quot;510f&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Horizontal scaling, also known as sharding&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;is the practice of adding more servers&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;923&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdAocL/btshCcDoIQJ/CJxsECdUTKR5Jaq66ampC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdAocL/btshCcDoIQJ/CJxsECdUTKR5Jaq66ampC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdAocL/btshCcDoIQJ/CJxsECdUTKR5Jaq66ampC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdAocL%2FbtshCcDoIQJ%2FCJxsECdUTKR5Jaq66ampC0%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;700&quot; height=&quot;462&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;923&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image source&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://amzn.eu/d/hLN5N8v&quot;&gt;&lt;b&gt;System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu&lt;/b&gt;&lt;/a&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;User data is allocated to a database server based on a particular sharding key. Anytime you access data, a hash function is used to find the corresponding shard.&lt;/p&gt;
&lt;p id=&quot;8821&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;In our example,&lt;span&gt;&amp;nbsp;&lt;/span&gt;user_id % 4&lt;span&gt;&amp;nbsp;&lt;/span&gt;is used as the hash function. If the result equals 0, shard 0 is used to store and fetch data. If the result equals 1, shard 1 is used and so on&amp;hellip;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceTFwN/btshBiRqnn9/DKfVdWVyXm7XHe09Rvkkx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceTFwN/btshBiRqnn9/DKfVdWVyXm7XHe09Rvkkx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceTFwN/btshBiRqnn9/DKfVdWVyXm7XHe09Rvkkx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceTFwN%2FbtshBiRqnn9%2FDKfVdWVyXm7XHe09Rvkkx0%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;700&quot; height=&quot;355&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image source&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://amzn.eu/d/hLN5N8v&quot;&gt;&lt;b&gt;System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p id=&quot;87c4&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Sharding is a good enough strategy but it has quite a few limitations:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li id=&quot;2346&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;b&gt;Resharding data&lt;/b&gt;: Resharding data is needed when 1) a single shard could no longer hold more data due to rapid growth. 2) Certain shards might experience shard exhaustion faster than others due to uneven data distribution. When shard exhaustion happens, it requires updating the sharding function and moving data around.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Consistent Hashing&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;is used to resolve this, which needs an article on its own.&lt;br /&gt;To read about this, kindly check out this amazing article &amp;mdash;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.toptal.com/big-data/consistent-hashing&quot;&gt;&lt;b&gt;A Guide To Consistent Hashing&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;7077&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;b&gt;Celebrity problem&lt;/b&gt;: Excessive access to a specific shard could cause server overload. Imagine data for Messi, CR7, and Neymar all end up on the same shard. For social applications, that shard will be overwhelmed with read operations. To solve this problem, we may need to allocate a shard for each celebrity. Each shard might even require further partition.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;d4c8&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;Logging, metrics, automation&lt;/h2&gt;
&lt;p id=&quot;77fc&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Monitoring error logs&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;is important because it helps to identify errors and problems in the system as our system and daily active users (DAU) grow.&lt;/p&gt;
&lt;p id=&quot;20da&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Metrics:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Collecting different types of metrics help us to gain business insights and understand the health status of the system.&lt;/p&gt;
&lt;p id=&quot;8dd7&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;When a system gets big and complex,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;we need to build or leverage automation tools to improve productivity.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;Each code check-in can be passed through some default checks and verified through automation, allowing teams to detect problems early. Besides, automating your build, test, deploy process, etc. could improve developer productivity significantly.&lt;/p&gt;
&lt;p id=&quot;76cd&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;With all these things in place our final system design:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;1542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnsnPO/btshWsY0gOu/Fdadn1H2jqlcwKjEYzDfh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnsnPO/btshWsY0gOu/Fdadn1H2jqlcwKjEYzDfh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnsnPO/btshWsY0gOu/Fdadn1H2jqlcwKjEYzDfh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnsnPO%2FbtshWsY0gOu%2FFdadn1H2jqlcwKjEYzDfh1%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;700&quot; height=&quot;854&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;1542&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image source&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://amzn.eu/d/hLN5N8v&quot;&gt;&lt;b&gt;System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742091</guid>
      <comments>https://sojw.tistory.com/1169742091#entry1169742091comment</comments>
      <pubDate>Tue, 30 May 2023 00:27:36 +0900</pubDate>
    </item>
    <item>
      <title>Publishing to Kafka &amp;mdash; Synchronous vs Asynchronous</title>
      <link>https://sojw.tistory.com/1169742090</link>
      <description>&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://medium.com/naukri-engineering/publishing-to-kafka-synchronous-vs-asynchronous-bf49c4e1af25&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/naukri-engineering/publishing-to-kafka-synchronous-vs-asynchronous-bf49c4e1af25&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1685373499709&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;Publishing to Kafka &amp;mdash; Synchronous vs Asynchronous&quot; data-og-description=&quot;Kafka is widely used for the asynchronous processing of events/messages.&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/naukri-engineering/publishing-to-kafka-synchronous-vs-asynchronous-bf49c4e1af25&quot; data-og-url=&quot;https://medium.com/naukri-engineering/publishing-to-kafka-synchronous-vs-asynchronous-bf49c4e1af25&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ewFdBn/hySNb8TEX9/Zo7jxuQyd2D5lUrEr1ubxk/img.png?width=761&amp;amp;height=261&amp;amp;face=0_0_761_261&quot;&gt;&lt;a href=&quot;https://medium.com/naukri-engineering/publishing-to-kafka-synchronous-vs-asynchronous-bf49c4e1af25&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/naukri-engineering/publishing-to-kafka-synchronous-vs-asynchronous-bf49c4e1af25&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ewFdBn/hySNb8TEX9/Zo7jxuQyd2D5lUrEr1ubxk/img.png?width=761&amp;amp;height=261&amp;amp;face=0_0_761_261');&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;Publishing to Kafka &amp;mdash; Synchronous vs Asynchronous&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Kafka is widely used for the asynchronous processing of events/messages.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교수치를 찾기 힘들었는데. 잘 나온 차트!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Impact:&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;5d15&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;The average response time of API endpoints was reduced to 3 milliseconds from 100 milliseconds.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1253&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oHjOy/btshE9l65pp/hE3sMVI91q2mCXyDQqPkhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oHjOy/btshE9l65pp/hE3sMVI91q2mCXyDQqPkhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oHjOy/btshE9l65pp/hE3sMVI91q2mCXyDQqPkhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoHjOy%2FbtshE9l65pp%2FhE3sMVI91q2mCXyDQqPkhk%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;700&quot; height=&quot;227&quot; data-origin-width=&quot;1253&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742090</guid>
      <comments>https://sojw.tistory.com/1169742090#entry1169742090comment</comments>
      <pubDate>Tue, 30 May 2023 00:19:03 +0900</pubDate>
    </item>
    <item>
      <title>Netflix Timestone</title>
      <link>https://sojw.tistory.com/1169742089</link>
      <description>&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://netflixtechblog.com/timestone-netflixs-high-throughput-low-latency-priority-queueing-system-with-built-in-support-1abf249ba95f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://netflixtechblog.com/timestone-netflixs-high-throughput-low-latency-priority-queueing-system-with-built-in-support-1abf249ba95f&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1685373246983&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;Timestone: Netflix&amp;rsquo;s High-Throughput, Low-Latency Priority Queueing System with Built-in Support&amp;hellip;&quot; data-og-description=&quot;by Kostas Christidis&quot; data-og-host=&quot;netflixtechblog.com&quot; data-og-source-url=&quot;https://netflixtechblog.com/timestone-netflixs-high-throughput-low-latency-priority-queueing-system-with-built-in-support-1abf249ba95f&quot; data-og-url=&quot;https://netflixtechblog.com/timestone-netflixs-high-throughput-low-latency-priority-queueing-system-with-built-in-support-1abf249ba95f&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bG9frS/hySNfKcDxk/guioA31RNGEtj0V18LPJrk/img.png?width=1200&amp;amp;height=632&amp;amp;face=0_0_1200_632&quot;&gt;&lt;a href=&quot;https://netflixtechblog.com/timestone-netflixs-high-throughput-low-latency-priority-queueing-system-with-built-in-support-1abf249ba95f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://netflixtechblog.com/timestone-netflixs-high-throughput-low-latency-priority-queueing-system-with-built-in-support-1abf249ba95f&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bG9frS/hySNfKcDxk/guioA31RNGEtj0V18LPJrk/img.png?width=1200&amp;amp;height=632&amp;amp;face=0_0_1200_632');&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;Timestone: Netflix&amp;rsquo;s High-Throughput, Low-Latency Priority Queueing System with Built-in Support&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;by Kostas Christidis&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;netflixtechblog.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h1 id=&quot;d511&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;System Architecture&lt;/h1&gt;
&lt;p id=&quot;fdcd&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Timestone is a gRPC-based service. We use protocol buffers to define the interface of our service and the structure of our request and response messages. The system diagram for the application is shown in&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Figure 2&lt;/b&gt;.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;519&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddUqh8/btshG72L9QU/K7I8znZu0lXm37oAq66eOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddUqh8/btshG72L9QU/K7I8znZu0lXm37oAq66eOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddUqh8/btshG72L9QU/K7I8znZu0lXm37oAq66eOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddUqh8%2FbtshG72L9QU%2FK7I8znZu0lXm37oAq66eOk%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;700&quot; height=&quot;260&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;519&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Figure 2.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Timestone system diagram. Arrows link all the components touched during a typical Timestone client-server interaction. Numbers in red indicate sequence steps. Identical numbers identify concurrent steps.&lt;/p&gt;</description>
      <category>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742089</guid>
      <comments>https://sojw.tistory.com/1169742089#entry1169742089comment</comments>
      <pubDate>Tue, 30 May 2023 00:16:46 +0900</pubDate>
    </item>
    <item>
      <title>System Design &amp;mdash; Design A Rate Limiter</title>
      <link>https://sojw.tistory.com/1169742088</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/geekculture/system-design-design-a-rate-limiter-81d200c9d392&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/geekculture/system-design-design-a-rate-limiter-81d200c9d392&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1684488023752&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;System Design &amp;mdash; Design A Rate Limiter&quot; data-og-description=&quot;Note: I have read this great book System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu in depth. So most of my definitions and images&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/geekculture/system-design-design-a-rate-limiter-81d200c9d392&quot; data-og-url=&quot;https://medium.com/geekculture/system-design-design-a-rate-limiter-81d200c9d392&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/i1JDH/hySGdlkYSz/1S0P7tVIwZxfdCZH2CLOs1/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628&quot;&gt;&lt;a href=&quot;https://medium.com/geekculture/system-design-design-a-rate-limiter-81d200c9d392&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/geekculture/system-design-design-a-rate-limiter-81d200c9d392&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/i1JDH/hySGdlkYSz/1S0P7tVIwZxfdCZH2CLOs1/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628');&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;System Design &amp;mdash; Design A Rate Limiter&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Note: I have read this great book System Design Interview &amp;mdash; An insider&amp;rsquo;s guide by Alex Xu in depth. So most of my definitions and images&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDn5FF/btsgBAMOME0/2GGBTStVQgapr3LHLo0Kk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDn5FF/btsgBAMOME0/2GGBTStVQgapr3LHLo0Kk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDn5FF/btsgBAMOME0/2GGBTStVQgapr3LHLo0Kk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDn5FF%2FbtsgBAMOME0%2F2GGBTStVQgapr3LHLo0Kk0%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;700&quot; height=&quot;235&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;469&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 id=&quot;f856&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Token Bucket Algorithm&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1066&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LrCxc/btsgCodKV1u/FDyrIUp1SkB2zLPwRP4g71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LrCxc/btsgCodKV1u/FDyrIUp1SkB2zLPwRP4g71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LrCxc/btsgCodKV1u/FDyrIUp1SkB2zLPwRP4g71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLrCxc%2FbtsgCodKV1u%2FFDyrIUp1SkB2zLPwRP4g71%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;1400&quot; height=&quot;1066&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1066&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd2rdy/btsgBzApB3m/lIuSa3xfH8TKKzKr3O6fk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd2rdy/btsgBzApB3m/lIuSa3xfH8TKKzKr3O6fk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd2rdy/btsgBzApB3m/lIuSa3xfH8TKKzKr3O6fk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd2rdy%2FbtsgBzApB3m%2FlIuSa3xfH8TKKzKr3O6fk0%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;458&quot; height=&quot;241&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;241&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;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>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742088</guid>
      <comments>https://sojw.tistory.com/1169742088#entry1169742088comment</comments>
      <pubDate>Fri, 19 May 2023 18:21:36 +0900</pubDate>
    </item>
    <item>
      <title>5 Important Microservices Design Patterns</title>
      <link>https://sojw.tistory.com/1169742087</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/javarevisited/5-important-microservices-design-patterns-c4d636b0051&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/javarevisited/5-important-microservices-design-patterns-c4d636b0051&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1684487407026&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;5 Important Microservices Design Patterns&quot; data-og-description=&quot;Microservices design patterns have become increasingly popular due to their ability to improve software agility, scalability, resilience&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/javarevisited/5-important-microservices-design-patterns-c4d636b0051&quot; data-og-url=&quot;https://medium.com/javarevisited/5-important-microservices-design-patterns-c4d636b0051&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cl5qXL/hySF9QKnpL/JkeCFeWs8BTm0c1baVh8h0/img.png?width=1050&amp;amp;height=652&amp;amp;face=0_0_1050_652&quot;&gt;&lt;a href=&quot;https://medium.com/javarevisited/5-important-microservices-design-patterns-c4d636b0051&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/javarevisited/5-important-microservices-design-patterns-c4d636b0051&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cl5qXL/hySF9QKnpL/JkeCFeWs8BTm0c1baVh8h0/img.png?width=1050&amp;amp;height=652&amp;amp;face=0_0_1050_652');&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;5 Important Microservices Design Patterns&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Microservices design patterns have become increasingly popular due to their ability to improve software agility, scalability, resilience&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;p id=&quot;f86c&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;Event Sourcing, Saga Pattern&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742087</guid>
      <comments>https://sojw.tistory.com/1169742087#entry1169742087comment</comments>
      <pubDate>Fri, 19 May 2023 18:19:12 +0900</pubDate>
    </item>
    <item>
      <title>API Design Practice</title>
      <link>https://sojw.tistory.com/1169742086</link>
      <description>&lt;p data-ke-size=&quot;size16&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;673&quot; data-origin-height=&quot;481&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uxO9i/btsf0W9tLp3/Kx9jeIttn4dhHhMFfQrkaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uxO9i/btsf0W9tLp3/Kx9jeIttn4dhHhMFfQrkaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uxO9i/btsf0W9tLp3/Kx9jeIttn4dhHhMFfQrkaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuxO9i%2Fbtsf0W9tLp3%2FKx9jeIttn4dhHhMFfQrkaK%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;673&quot; height=&quot;481&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;481&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/api-center/api-design-practice-7fce69e6336c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/api-center/api-design-practice-7fce69e6336c&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1684129921346&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;API Design Practice&quot; data-og-description=&quot;A practical guide to API QA and the design of stable, coherent and composable business resource APIs&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/api-center/api-design-practice-7fce69e6336c&quot; data-og-url=&quot;https://medium.com/api-center/api-design-practice-7fce69e6336c&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kALLN/hySCRIQoDM/Ol1fOpKWKee3jOKy7Douc1/img.png?width=673&amp;amp;height=481&amp;amp;face=0_0_673_481&quot;&gt;&lt;a href=&quot;https://medium.com/api-center/api-design-practice-7fce69e6336c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/api-center/api-design-practice-7fce69e6336c&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kALLN/hySCRIQoDM/Ol1fOpKWKee3jOKy7Douc1/img.png?width=673&amp;amp;height=481&amp;amp;face=0_0_673_481');&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;API Design Practice&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A practical guide to API QA and the design of stable, coherent and composable business resource APIs&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;</description>
      <category>emotional developer/detect-Web</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742086</guid>
      <comments>https://sojw.tistory.com/1169742086#entry1169742086comment</comments>
      <pubDate>Mon, 15 May 2023 14:52:34 +0900</pubDate>
    </item>
    <item>
      <title>SQL Performance Tuning</title>
      <link>https://sojw.tistory.com/1169742085</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. IN 대신 EXISTS를 사용하여 데이터의 존재를 확인하십시오.&lt;br /&gt;2. SELECT 문에서 *를 사용하지 마십시오.&lt;span&gt;&amp;nbsp;&lt;/span&gt;필요한 열의 이름을 지정하십시오.&lt;br /&gt;3. 적절한 데이터 유형을 선택합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;예를 들어 문자열을 저장하려면 텍스트 데이터 유형 대신 varchar를 사용하십시오.&lt;span&gt;&amp;nbsp;&lt;/span&gt;큰 데이터(8000자 이상)를 저장해야 할 때마다 텍스트 데이터 유형을 사용하십시오.&lt;br /&gt;4. 두 데이터 유형 모두 char 및 varchar만큼 이중 메모리를 사용하므로 가능하면 nchar 및 nvarchar를 사용하지 마십시오.&lt;br /&gt;5. 고정 길이 필드에서 NULL을 피하십시오.&lt;span&gt;&amp;nbsp;&lt;/span&gt;NULL이 요구되는 경우에는 NULL에 대한 공간을 적게 차지하는 가변 길이(varchar) 필드를 사용하십시오.&lt;br /&gt;6. 절을 피하십시오.&lt;span&gt;&amp;nbsp;&lt;/span&gt;집계 결과를 추가로 필터링하려면 having 절이 필요합니다.&lt;br /&gt;7. 클러스터형 및 비클러스터형 인덱스를 만듭니다.&lt;br /&gt;8. 클러스터형 인덱스에서 사용되는 필드가 비클러스터형 인덱스에서도 사용될 수 있으므로 클러스터형 인덱스를 작게 유지하십시오.&lt;br /&gt;9. 대부분의 선택적 열은 비클러스터형 인덱스의 키에서 가장 왼쪽에 배치해야 합니다.&lt;br /&gt;10. 사용하지 않는 인덱스를 삭제합니다.&lt;br /&gt;11. 문자 대신 정수 값이 있는 열에 인덱스를 만드는 것이 좋습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;정수 값은 문자 값보다 적은 오버헤드를 사용합니다.&lt;br /&gt;12. 하위 쿼리 대신 조인을 사용합니다.&lt;br /&gt;13. 조인으로 생성되는 결과 테이블의 크기를 제한하려면 WHERE 식을 사용하십시오.&lt;br /&gt;14. 테이블에 삽입할 때 TABLOCKX를 사용하고 병합할 때 TABLOCK을 사용하십시오.&lt;br /&gt;15. 테이블에서 데이터를 쿼리하는 동안 WITH(NOLOCK)를 사용합니다.&lt;br /&gt;16. SET NOCOUNT ON을 사용하고 TRY-CATCH를 사용하여 교착 상태를 피하십시오.&lt;br /&gt;17. 커서는 성능이 매우 느리므로 커서를 사용하지 마십시오.&lt;br /&gt;18. 임시 테이블 대신 테이블 변수를 사용하십시오.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Temp 테이블을 사용하려면 시간이 많이 걸리는 작업인 TempDb 데이터베이스와의 상호 작용이 필요했습니다.&lt;br /&gt;19. 가능하면 UNION 대신 UNION ALL을 사용하십시오.&lt;br /&gt;20. SQL 개체 이름 앞에 스키마 이름을 사용합니다.&lt;br /&gt;21. 자주 사용하는 데이터와 더 복잡한 쿼리에는 저장 프로시저를 사용하십시오.&lt;br /&gt;22. 트랜잭션이 처리 테이블 데이터를 잠그고 교착 상태가 발생할 수 있으므로 트랜잭션을 가능한 작게 유지하십시오.&lt;br /&gt;23. 사용자 정의 저장 프로시저 이름을 접두사 &quot;sp_&quot;로 사용하지 마십시오. SQL 서버는 먼저 마스터 데이터베이스에서 사용자 정의 프로시저를 검색한 다음 현재 세션 데이터베이스에서 검색하기 때문입니다.&lt;br /&gt;24. 상관 관계가 없는 스칼라 하위 쿼리를 사용하지 마십시오.&lt;span&gt;&amp;nbsp;&lt;/span&gt;이 쿼리를 기본 쿼리의 일부가 아닌 별도의 쿼리로 사용하고 출력을 변수에 저장합니다. 이 변수는 기본 쿼리 또는 일괄 처리의 이후 부분에서 참조할 수 있습니다.&lt;br /&gt;25. 다중 문 테이블 값 함수(TVF)를 피하십시오.&lt;span&gt;&amp;nbsp;&lt;/span&gt;다중 문 TVF는 인라인 TVF보다 비용이 많이 듭니다.&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;a href=&quot;https://connect2grp.medium.com/sql-performance-tuning-c200e7a8a556&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://connect2grp.medium.com/sql-performance-tuning-c200e7a8a556&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1684129812578&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;SQL Performance Tuning&quot; data-og-description=&quot;SQL performance tuning is a process of optimizing SQL queries to ensure they execute as fast as possible. There are many factors that&amp;hellip;&quot; data-og-host=&quot;connect2grp.medium.com&quot; data-og-source-url=&quot;https://connect2grp.medium.com/sql-performance-tuning-c200e7a8a556&quot; data-og-url=&quot;https://connect2grp.medium.com/sql-performance-tuning-c200e7a8a556&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bKtk9J/hySCO6pwtf/Owy6oC9DFTPp19fk6AZ4Dk/img.png?width=749&amp;amp;height=358&amp;amp;face=0_0_749_358&quot;&gt;&lt;a href=&quot;https://connect2grp.medium.com/sql-performance-tuning-c200e7a8a556&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://connect2grp.medium.com/sql-performance-tuning-c200e7a8a556&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bKtk9J/hySCO6pwtf/Owy6oC9DFTPp19fk6AZ4Dk/img.png?width=749&amp;amp;height=358&amp;amp;face=0_0_749_358');&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;SQL Performance Tuning&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SQL performance tuning is a process of optimizing SQL queries to ensure they execute as fast as possible. There are many factors that&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;connect2grp.medium.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>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742085</guid>
      <comments>https://sojw.tistory.com/1169742085#entry1169742085comment</comments>
      <pubDate>Mon, 15 May 2023 14:51:16 +0900</pubDate>
    </item>
    <item>
      <title>Review of Java Features From 11 to 17</title>
      <link>https://sojw.tistory.com/1169742084</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDK 8에서 벗어나질 못하는 환경들이 많음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적 선호도.&lt;/p&gt;
&lt;h2 id=&quot;1272&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Switch expressions (Java SE 14, JEP-361)&lt;/b&gt;&lt;/h2&gt;
&lt;h2 id=&quot;f7c6&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;Records (Java SE 16, JEP-395)&lt;/h2&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://medium.com/@omernaci/review-of-java-features-from-11-to-17-a7ccbb9af133&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@omernaci/review-of-java-features-from-11-to-17-a7ccbb9af133&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1684128958830&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;Review of Java Features From 11 to 17&quot; data-og-description=&quot;Java is a powerful and widely-used programming language that has been evolving over the years to stay relevant and up-to-date with the&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@omernaci/review-of-java-features-from-11-to-17-a7ccbb9af133&quot; data-og-url=&quot;https://medium.com/@omernaci/review-of-java-features-from-11-to-17-a7ccbb9af133&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cM5q2L/hySCXPOgIx/PNnqNVWgUFkLo2D3hR92r1/img.jpg?width=1200&amp;amp;height=915&amp;amp;face=0_0_1200_915,https://scrap.kakaocdn.net/dn/EalG6/hySCOrNqGE/wJD5PmtYnUIxx6UUNcK6SK/img.jpg?width=1358&amp;amp;height=905&amp;amp;face=0_0_1358_905,https://scrap.kakaocdn.net/dn/yvkXN/hySCOrNqNT/lnxFJ4s5Z6KkEHMOOPv9Qk/img.jpg?width=1358&amp;amp;height=905&amp;amp;face=0_0_1358_905&quot;&gt;&lt;a href=&quot;https://medium.com/@omernaci/review-of-java-features-from-11-to-17-a7ccbb9af133&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@omernaci/review-of-java-features-from-11-to-17-a7ccbb9af133&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cM5q2L/hySCXPOgIx/PNnqNVWgUFkLo2D3hR92r1/img.jpg?width=1200&amp;amp;height=915&amp;amp;face=0_0_1200_915,https://scrap.kakaocdn.net/dn/EalG6/hySCOrNqGE/wJD5PmtYnUIxx6UUNcK6SK/img.jpg?width=1358&amp;amp;height=905&amp;amp;face=0_0_1358_905,https://scrap.kakaocdn.net/dn/yvkXN/hySCOrNqNT/lnxFJ4s5Z6KkEHMOOPv9Qk/img.jpg?width=1358&amp;amp;height=905&amp;amp;face=0_0_1358_905');&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;Review of Java Features From 11 to 17&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Java is a powerful and widely-used programming language that has been evolving over the years to stay relevant and up-to-date with the&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;</description>
      <category>emotional developer/detect-Java</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742084</guid>
      <comments>https://sojw.tistory.com/1169742084#entry1169742084comment</comments>
      <pubDate>Mon, 15 May 2023 14:37:26 +0900</pubDate>
    </item>
    <item>
      <title>Migrating Critical Traffic At Scale with No Downtime</title>
      <link>https://sojw.tistory.com/1169742083</link>
      <description>&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;Netflix Tech Blog Post&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;part 2 update 되면 추가,,&lt;/b&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;&lt;a href=&quot;https://netflixtechblog.com/migrating-critical-traffic-at-scale-with-no-downtime-part-1-ba1c7a1c7835&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://netflixtechblog.com/migrating-critical-traffic-at-scale-with-no-downtime-part-1-ba1c7a1c7835&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1684128835924&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;Migrating Critical Traffic At Scale with No Downtime &amp;mdash; Part 1&quot; data-og-description=&quot;Shyam Gala, Javier Fernandez-Ivern, Anup Rokkam Pratap, Devang Shah&quot; data-og-host=&quot;netflixtechblog.com&quot; data-og-source-url=&quot;https://netflixtechblog.com/migrating-critical-traffic-at-scale-with-no-downtime-part-1-ba1c7a1c7835&quot; data-og-url=&quot;https://netflixtechblog.com/migrating-critical-traffic-at-scale-with-no-downtime-part-1-ba1c7a1c7835&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UgqUy/hySCTfx9RW/dHAqgt0WjFWtU4ZIOrJXkk/img.png?width=1075&amp;amp;height=411&amp;amp;face=0_0_1075_411&quot;&gt;&lt;a href=&quot;https://netflixtechblog.com/migrating-critical-traffic-at-scale-with-no-downtime-part-1-ba1c7a1c7835&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://netflixtechblog.com/migrating-critical-traffic-at-scale-with-no-downtime-part-1-ba1c7a1c7835&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UgqUy/hySCTfx9RW/dHAqgt0WjFWtU4ZIOrJXkk/img.png?width=1075&amp;amp;height=411&amp;amp;face=0_0_1075_411');&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;Migrating Critical Traffic At Scale with No Downtime &amp;mdash; Part 1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Shyam Gala, Javier Fernandez-Ivern, Anup Rokkam Pratap, Devang Shah&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;netflixtechblog.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>emotional developer/detect-server</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742083</guid>
      <comments>https://sojw.tistory.com/1169742083#entry1169742083comment</comments>
      <pubDate>Mon, 15 May 2023 14:35:15 +0900</pubDate>
    </item>
    <item>
      <title>5 Design Patterns in Java that Solve Major Problems</title>
      <link>https://sojw.tistory.com/1169742082</link>
      <description>&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://levelup.gitconnected.com/5-design-patterns-in-java-that-solve-major-problems-8e85132cfb48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://levelup.gitconnected.com/5-design-patterns-in-java-that-solve-major-problems-8e85132cfb48&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1683251058235&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;5 Design Patterns in Java that Solve Major Problems!&quot; data-og-description=&quot;In a previous post, I showed you how the OOP world looks like. OOP is a pretty convenient paradigm for identifying requirements while also&amp;hellip;&quot; data-og-host=&quot;levelup.gitconnected.com&quot; data-og-source-url=&quot;https://levelup.gitconnected.com/5-design-patterns-in-java-that-solve-major-problems-8e85132cfb48&quot; data-og-url=&quot;https://levelup.gitconnected.com/5-design-patterns-in-java-that-solve-major-problems-8e85132cfb48&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cDdxep/hySvkZiguP/aztus3R9c2EOZuY4psIFvk/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800&quot;&gt;&lt;a href=&quot;https://levelup.gitconnected.com/5-design-patterns-in-java-that-solve-major-problems-8e85132cfb48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://levelup.gitconnected.com/5-design-patterns-in-java-that-solve-major-problems-8e85132cfb48&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cDdxep/hySvkZiguP/aztus3R9c2EOZuY4psIFvk/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800');&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;5 Design Patterns in Java that Solve Major Problems!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In a previous post, I showed you how the OOP world looks like. OOP is a pretty convenient paradigm for identifying requirements while also&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;levelup.gitconnected.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 id=&quot;b45b&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;1. Singleton Pattern&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;2. Observer Pattern&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;3. Strategy Pattern&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;4. Decorater Pattern&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;5. Factory Pattern&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;</description>
      <category>emotional developer/detect-Java</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742082</guid>
      <comments>https://sojw.tistory.com/1169742082#entry1169742082comment</comments>
      <pubDate>Fri, 5 May 2023 10:45:23 +0900</pubDate>
    </item>
    <item>
      <title>Spring Data JPA Optimize</title>
      <link>https://sojw.tistory.com/1169742081</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@eidan.khan659/how-to-optimize-performance-with-spring-data-jpa-c615db786f7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@eidan.khan659/how-to-optimize-performance-with-spring-data-jpa-c615db786f7&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1683250675536&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;How to Optimize Performance with Spring Data JPA&quot; data-og-description=&quot;Spring Data JPA is a powerful tool for working with databases in Java applications. It provides an easy-to-use and flexible interface for&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@eidan.khan659/how-to-optimize-performance-with-spring-data-jpa-c615db786f7&quot; data-og-url=&quot;https://medium.com/@eidan.khan659/how-to-optimize-performance-with-spring-data-jpa-c615db786f7&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cXtb3K/hySvplU68x/DGEkjYtMq9hB2odYXCtSDK/img.png?width=1200&amp;amp;height=630&amp;amp;face=800_369_850_425&quot;&gt;&lt;a href=&quot;https://medium.com/@eidan.khan659/how-to-optimize-performance-with-spring-data-jpa-c615db786f7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@eidan.khan659/how-to-optimize-performance-with-spring-data-jpa-c615db786f7&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cXtb3K/hySvplU68x/DGEkjYtMq9hB2odYXCtSDK/img.png?width=1200&amp;amp;height=630&amp;amp;face=800_369_850_425');&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;How to Optimize Performance with Spring Data JPA&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Data JPA is a powerful tool for working with databases in Java applications. It provides an easy-to-use and flexible interface for&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 id=&quot;91b4&quot; style=&quot;background-color: #ffffff; color: #292929; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;1. Avoid N+1 Selects Problem&lt;br /&gt;2. Use Lazy Loading&lt;br /&gt;3. Use Caching&lt;br /&gt;4. Use Paging and Sorting&lt;/h4&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;index 최적화&lt;/li&gt;
&lt;li&gt;Join 최적화...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>emotional developer/detect-Java</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742081</guid>
      <comments>https://sojw.tistory.com/1169742081#entry1169742081comment</comments>
      <pubDate>Fri, 5 May 2023 10:39:57 +0900</pubDate>
    </item>
    <item>
      <title>Spring Security Filter Flow</title>
      <link>https://sojw.tistory.com/1169742080</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;718&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3Mfms/btsdNvAMkb8/Zw73pwKh3b8YJdVf9RGBZK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3Mfms/btsdNvAMkb8/Zw73pwKh3b8YJdVf9RGBZK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3Mfms/btsdNvAMkb8/Zw73pwKh3b8YJdVf9RGBZK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3Mfms%2FbtsdNvAMkb8%2FZw73pwKh3b8YJdVf9RGBZK%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;1050&quot; height=&quot;718&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;718&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Good!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@gaganjain9319/spring-security-features-and-secure-rest-api-using-spring-security-in-java-e4c812ed085&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@gaganjain9319/spring-security-features-and-secure-rest-api-using-spring-security-in-java-e4c812ed085&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1683138625353&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;Spring security features and secure Rest API using spring security in JAVA&quot; data-og-description=&quot;Spring Security is a powerful and widely used security framework for Java applications that provides authentication, authorisation, and&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@gaganjain9319/spring-security-features-and-secure-rest-api-using-spring-security-in-java-e4c812ed085&quot; data-og-url=&quot;https://medium.com/@gaganjain9319/spring-security-features-and-secure-rest-api-using-spring-security-in-java-e4c812ed085&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/8Wtgf/hyStPSZ1Qd/psprZy2mAMznfSc2uKZeKk/img.jpg?width=1050&amp;amp;height=718&amp;amp;face=0_0_1050_718&quot;&gt;&lt;a href=&quot;https://medium.com/@gaganjain9319/spring-security-features-and-secure-rest-api-using-spring-security-in-java-e4c812ed085&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@gaganjain9319/spring-security-features-and-secure-rest-api-using-spring-security-in-java-e4c812ed085&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/8Wtgf/hyStPSZ1Qd/psprZy2mAMznfSc2uKZeKk/img.jpg?width=1050&amp;amp;height=718&amp;amp;face=0_0_1050_718');&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;Spring security features and secure Rest API using spring security in JAVA&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Security is a powerful and widely used security framework for Java applications that provides authentication, authorisation, and&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;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>emotional developer/detect-pattern</category>
      <author>성게군.</author>
      <guid isPermaLink="true">https://sojw.tistory.com/1169742080</guid>
      <comments>https://sojw.tistory.com/1169742080#entry1169742080comment</comments>
      <pubDate>Thu, 4 May 2023 03:30:50 +0900</pubDate>
    </item>
  </channel>
</rss>