<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>seuthootdev 님의 블로그</title>
    <link>https://seuthootdev.tistory.com/</link>
    <description>seuthootdev 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Sun, 6 Sep 2026 00:54:48 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>seuthootdev</managingEditor>
    <image>
      <title>seuthootdev 님의 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/8036541/attach/20190489e2bf4eb388ff6425a8712306</url>
      <link>https://seuthootdev.tistory.com</link>
    </image>
    <item>
      <title>항해+ 백엔드 코드 9주차 회고 : Kafka 메세지 큐</title>
      <link>https://seuthootdev.tistory.com/11</link>
      <description>&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;&lt;b&gt;항해 20만원 할인 추천인코드: NYFKU8&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 주 과제는 기존에 구현된 이벤트 기반 로직을 &lt;b&gt;Kafka&lt;/b&gt; 메세지 큐를 활용하여 리팩토링 하는 과제였습니다.&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Kafka&lt;/b&gt;는 대규모 실시간 데이터 스트리밍을 위한 &lt;b&gt;분산 메시징 시스템&lt;/b&gt;으로, 높은 처리량과 안정성을 제공하는 것이 특징입니다. 특히 이벤트 기반 아키텍처에서 서비스 간 결합도를 낮추고, 장애가 발생했을 때에도 메시지를 안정적으로 처리할 수 있도록 설계되어 있습니다&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;355&quot; data-start=&quot;337&quot; data-ke-size=&quot;size23&quot;&gt;Kafka Overview&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btHTE6/btsQtiaBChE/y6sz9yMOiZHEF6NsOZA4C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btHTE6/btsQtiaBChE/y6sz9yMOiZHEF6NsOZA4C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btHTE6/btsQtiaBChE/y6sz9yMOiZHEF6NsOZA4C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtHTE6%2FbtsQtiaBChE%2Fy6sz9yMOiZHEF6NsOZA4C0%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;1336&quot; height=&quot;300&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1462&quot; data-start=&quot;356&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;550&quot; data-start=&quot;356&quot;&gt;&lt;b&gt;Producer &amp;amp; Consumer&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;550&quot; data-start=&quot;386&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;429&quot; data-start=&quot;386&quot;&gt;Producer는 메시지를 Kafka 브로커에 발행하는 주체입니다.&lt;/li&gt;
&lt;li data-end=&quot;474&quot; data-start=&quot;432&quot;&gt;Consumer는 브로커에 적재된 메시지를 읽어오는 서비스입니다.&lt;/li&gt;
&lt;li data-end=&quot;550&quot; data-start=&quot;477&quot;&gt;Consumer는 메시지의 처리 위치를 추적하기 위해 offset을 사용하며, 이를 커밋하여 재처리나 누락을 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;748&quot; data-start=&quot;552&quot;&gt;&lt;b&gt;Broker&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;748&quot; data-start=&quot;569&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;638&quot; data-start=&quot;569&quot;&gt;Kafka 서버의 단위로, Producer의 메시지를 받아 디스크에 저장하고 Consumer 요청에 따라 전달합니다.&lt;/li&gt;
&lt;li data-end=&quot;748&quot; data-start=&quot;641&quot;&gt;클러스터 내부에서는 &lt;b&gt;Controller&lt;/b&gt;(장애 브로커 감지 및 리더 파티션 재분배), &lt;b&gt;Coordinator&lt;/b&gt;(컨슈머 그룹 모니터링 및 파티션 재할당) 같은 역할을 수행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;974&quot; data-start=&quot;750&quot;&gt;&lt;b&gt;&lt;b&gt;Topic &amp;amp; Partition&lt;/b&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dST0Pw/btsQqnLuWWA/koa2wMEuBw3D62AEuYimk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dST0Pw/btsQqnLuWWA/koa2wMEuBw3D62AEuYimk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dST0Pw/btsQqnLuWWA/koa2wMEuBw3D62AEuYimk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdST0Pw%2FbtsQqnLuWWA%2Fkoa2wMEuBw3D62AEuYimk1%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;1356&quot; height=&quot;536&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;974&quot; data-start=&quot;778&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;827&quot; data-start=&quot;778&quot;&gt;메시지는 토픽 단위로 분류되고, 각 토픽은 여러 개의 &lt;b&gt;파티션&lt;/b&gt;으로 나뉩니다.&lt;/li&gt;
&lt;li data-end=&quot;910&quot; data-start=&quot;830&quot;&gt;파티션을 활용하면 &lt;b&gt;병렬 처리&lt;/b&gt;가 가능해 대용량 트래픽을 빠르게 처리할 수 있으며, 같은 파티션 내에서는 &lt;b&gt;순차성&lt;/b&gt;이 보장됩니다.&lt;/li&gt;
&lt;li data-end=&quot;974&quot; data-start=&quot;913&quot;&gt;메시지 키를 활용하면 특정 자원(ID 등)에 대해 순서가 중요한 이벤트는 순차성을 보장할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1128&quot; data-start=&quot;976&quot;&gt;&lt;b&gt;&lt;b&gt;Consumer Group&lt;/b&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;826&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUxD2t/btsQruJSofB/I9n8DQa2yfjvEFmxhVX8Y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUxD2t/btsQruJSofB/I9n8DQa2yfjvEFmxhVX8Y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUxD2t/btsQruJSofB/I9n8DQa2yfjvEFmxhVX8Y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUxD2t%2FbtsQruJSofB%2FI9n8DQa2yfjvEFmxhVX8Y1%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;826&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;826&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1128&quot; data-start=&quot;1001&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1042&quot; data-start=&quot;1001&quot;&gt;하나의 토픽을 여러 서비스가 구독할 수 있도록 그룹화한 개념입니다.&lt;/li&gt;
&lt;li data-end=&quot;1128&quot; data-start=&quot;1045&quot;&gt;같은 토픽의 메시지를 결제 서비스, 상품 서비스 등 여러 애플리케이션이 동시에 처리할 수 있으며, 그룹 내에서 파티션은 컨슈머에게 분배됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1259&quot; data-start=&quot;1130&quot;&gt;&lt;b&gt;Rebalancing&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1259&quot; data-start=&quot;1152&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1209&quot; data-start=&quot;1152&quot;&gt;새로운 Consumer가 추가되거나 장애가 발생했을 때 파티션의 소유권을 재분배하는 과정입니다.&lt;/li&gt;
&lt;li data-end=&quot;1259&quot; data-start=&quot;1212&quot;&gt;단, 리밸런싱이 일어나는 동안에는 메시지 처리가 중단되므로 주의가 필요합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1462&quot; data-start=&quot;1261&quot;&gt;&lt;b&gt;Cluster &amp;amp; Replication&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1462&quot; data-start=&quot;1293&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1339&quot; data-start=&quot;1293&quot;&gt;Kafka는 고가용성을 위해 여러 Broker를 묶어 클러스터를 구성합니다.&lt;/li&gt;
&lt;li data-end=&quot;1462&quot; data-start=&quot;1342&quot;&gt;각 파티션은 &lt;b&gt;리더(Leader) Replica&lt;/b&gt;와 &lt;b&gt;팔로워(Follower) Replica&lt;/b&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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;STEP 17 카프카 기초 학습 및 활용&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실시간 주문정보(이커머스) &amp;amp; 예약정보(콘서트)를 카프카 메시지로 발행하도록 변경합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;카프카에 대한 기초 개념을 학습하고 문서로 작성합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬에서 카프카를 설치하고 기본적인 기능을 수행해봅니다.&lt;/li&gt;
&lt;li&gt;어플리케이션에서 카프카를 연결하여 Producer &amp;amp; Consumer를 동작시켜봅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;STEP 18 카프카를 활용하여 비즈니스 프로세스 개선&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 프로젝트의 대용량 트래픽 프로세스를 카프카를 활용하도록 변경해봅니다.&lt;/li&gt;
&lt;li&gt;개선한 내용에 대한 설계 문서(비즈니스 시퀀스 다이어그램, 카프카 구성 등)를 작성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;260&quot; data-end=&quot;295&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-start=&quot;260&quot; data-end=&quot;278&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/18&quot;&gt;Step17 PR&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-start=&quot;279&quot; data-end=&quot;295&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/19&quot;&gt;Step18 PR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1757412625808&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;Step18 by seuthootDev &amp;middot; Pull Request #19 &amp;middot; seuthootDev/hanghae-plus-backend&quot; data-og-description=&quot;  PR 제목 규칙 [STEP18] 정승훈 - (e-commerce) STEP 17 카프카 기초 학습 및 활용 [✅] 카프카에 대한 기본 개념 학습 문서 작성 문서작성 7d898fa | kafka 기본예제 ed4b46b | kafka 토픽,스트림 예제 36df67b [✅] &quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/19&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/19&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bziP1l/hyZI5zrewZ/QRaaROWxp3tAMDzyUAfCJ0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/U1QLa/hyZIRPgonS/8Keahl34P4JhqHhKCYtPC0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/19&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bziP1l/hyZI5zrewZ/QRaaROWxp3tAMDzyUAfCJ0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/U1QLa/hyZIRPgonS/8Keahl34P4JhqHhKCYtPC0/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;Step18 by seuthootDev &amp;middot; Pull Request #19 &amp;middot; seuthootDev/hanghae-plus-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  PR 제목 규칙 [STEP18] 정승훈 - (e-commerce) STEP 17 카프카 기초 학습 및 활용 [✅] 카프카에 대한 기본 개념 학습 문서 작성 문서작성 7d898fa | kafka 기본예제 ed4b46b | kafka 토픽,스트림 예제 36df67b [✅]&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;figure id=&quot;og_1757412621940&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;Step17 by seuthootDev &amp;middot; Pull Request #18 &amp;middot; seuthootDev/hanghae-plus-backend&quot; data-og-description=&quot;  PR 제목 규칙 [STEP17] 정승훈 - (e-commerce) STEP 17 카프카 기초 학습 및 활용 [✅] 카프카에 대한 기본 개념 학습 문서 작성 문서작성 7d898fa | kafka 기본예제 ed4b46b | kafka 토픽,스트림 예제 36df67b [✅] &quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/18&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/18&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bIrppA/hyZIWC3lZO/ZkcMgteOkl34kECg5y0CkK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/cs9Iaq/hyZIQQnuy9/rAbCiNKoMgfKNJhhcP4zRk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/18&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/18&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bIrppA/hyZIWC3lZO/ZkcMgteOkl34kECg5y0CkK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/cs9Iaq/hyZIQQnuy9/rAbCiNKoMgfKNJhhcP4zRk/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;Step17 by seuthootDev &amp;middot; Pull Request #18 &amp;middot; seuthootDev/hanghae-plus-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  PR 제목 규칙 [STEP17] 정승훈 - (e-commerce) STEP 17 카프카 기초 학습 및 활용 [✅] 카프카에 대한 기본 개념 학습 문서 작성 문서작성 7d898fa | kafka 기본예제 ed4b46b | kafka 토픽,스트림 예제 36df67b [✅]&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;h3 data-end=&quot;46&quot; data-start=&quot;38&quot; data-ke-size=&quot;size23&quot;&gt;회고&lt;/h3&gt;
&lt;p data-end=&quot;203&quot; data-start=&quot;47&quot; data-ke-size=&quot;size16&quot;&gt;Kafka를 적용하면서 단순한 메시지 큐를 넘어 &lt;b&gt;대용량 트래픽 처리와 서비스 간 책임 분리&lt;/b&gt;에 강점이 있다는 걸 느꼈습니다. 파티션과 Consumer Group 설계가 성능과 직결된다는 점이 인상 깊었고, 리밸런싱과 같은 운영 이슈도 고민할 필요가 있다는 걸 배웠습니다.&lt;/p&gt;</description>
      <category>항해+</category>
      <category>DB</category>
      <category>Kafka</category>
      <category>레디스</category>
      <category>부트캠프</category>
      <category>부트캠프할인</category>
      <category>추천인코드</category>
      <category>카프카</category>
      <category>항해+</category>
      <category>항해추천인</category>
      <category>항해할인</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/11</guid>
      <comments>https://seuthootdev.tistory.com/11#entry11comment</comments>
      <pubDate>Tue, 9 Sep 2025 19:11:56 +0900</pubDate>
    </item>
    <item>
      <title>항해+ 백엔드 코드 8주차 회고 : Event 기반 Transaction</title>
      <link>https://seuthootdev.tistory.com/10</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;&lt;b&gt;항해 20만원 할인 추천인코드: NYFKU8&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/i&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&gt;이벤트 기반 아키텍처&lt;/span&gt;&lt;/b&gt;&lt;span&gt;로 리팩토링하는 것이었습니다&lt;/span&gt;. &lt;span&gt;단순히 하나의 트랜잭션으로 처리하던 복잡한 로직을 이벤트 발행과 구독 모델로 분리하면서, &lt;b&gt;&lt;span&gt;트랜잭션 범위&lt;/span&gt;&lt;/b&gt;&lt;span&gt;를 축소하고 &lt;/span&gt;&lt;b&gt;&lt;span&gt;관심사를 분리&lt;/span&gt;&lt;/b&gt;&lt;span&gt;하였습니다.&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;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image (1).webp&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uQsst/btsQeE6LYDF/fcCNbKsyhQn1ZJW0ZLxL51/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uQsst/btsQeE6LYDF/fcCNbKsyhQn1ZJW0ZLxL51/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uQsst/btsQeE6LYDF/fcCNbKsyhQn1ZJW0ZLxL51/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuQsst%2FbtsQeE6LYDF%2FfcCNbKsyhQn1ZJW0ZLxL51%2Fimg.webp&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;1284&quot; height=&quot;352&quot; data-filename=&quot;image (1).webp&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Event 기반 흐름 제어&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;Event 를 발행 및 구독하는 모델링을 통해 코드의 강한 결합을 분리함&lt;/li&gt;
&lt;li&gt;Event 에 의해 본인의 관심사만 수행하도록 하여 비즈니스 로직간의 의존을 느슨하게 함&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;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;특정 작업이 완료되었을 때, 후속 작업이 이벤트에 의해 trigger 되도록 구성함으로써 과도하게 많은 비즈니스 로직을 알고 있을 필요 없음&lt;/li&gt;
&lt;li&gt;외부 API 호출 및 부가 로직의 실패나 지연이 주요 비즈니스 로직(트랜잭션)에 영향을 주지 않도록 구성할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1756643078236&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OrderPaymentService {
	Transaction {
		fun 주문_결제() {
			유저_포인트_차감();
			결제_정보_저장();
			주문_상태_변경();
			
			결제_완료_이벤트_발행();
		}
	}
}


class OrderPaymentEventListener {

	TransactionEventListener(AFTER_COMMIT) {
		Async {
		  // Notify Service
			fun 주문_정보_전달(결제_완료_이벤트)
		}
	}
	
	TransactionEventListener(AFTER_COMMIT) {
		Async {
			fun 결제_완료_알림톡_발송(결제_완료_이벤트)
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OrderPaymentService에서 &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 data-ke-size=&quot;size23&quot;&gt;Implementation&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트를 활용해서 단순히 &lt;b&gt;부가 로직&lt;/b&gt;을 분리할 뿐만 아니라, 여러 도메인이 결합하여 구성된 &lt;b&gt;핵심 로직&lt;/b&gt;을 각 도메인별로 관심사와 트랜잭션을 분리하도록 구성할 수도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image (2).webp&quot; data-origin-width=&quot;1742&quot; data-origin-height=&quot;978&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lN7zD/btsQfeNB0KA/Knu0PEcZhX8u59DkOTVoDK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lN7zD/btsQfeNB0KA/Knu0PEcZhX8u59DkOTVoDK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lN7zD/btsQfeNB0KA/Knu0PEcZhX8u59DkOTVoDK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlN7zD%2FbtsQfeNB0KA%2FKnu0PEcZhX8u59DkOTVoDK%2Fimg.webp&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;1742&quot; height=&quot;978&quot; data-filename=&quot;image (2).webp&quot; data-origin-width=&quot;1742&quot; data-origin-height=&quot;978&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Service A 로직이 수행된 이후에 이벤트를 발행하여 Service B와 Service C가 각각 로직을 수행함&lt;/li&gt;
&lt;li&gt;만약 Service B 로직을 수행한 이후에 Service C 로직을 수행해야 한다면?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;만약 이벤트에 의해 파생된 작업이 실패하였을 때, 원본 작업 또한 실패 처리를 해야 한다면 이를 위한 처리가 필요함 ( &lt;b&gt;keyword : 보상 트랜잭션, SAGA 패턴&lt;/b&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;&lt;b&gt;이번주 과제 내용&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;STEP 15 Application Event&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실시간 주문정보(이커머스) &amp;amp; 예약정보(콘서트)를 데이터 플랫폼에 전송(mock API 호출)하는 요구사항을 이벤트를 활용하여 트랜잭션과 관심사를 분리하여 서비스를 개선합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;STEP 16 Transaction Diagnosis&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스의 확장에 따라 어플리케이션 서버와 DB를 도메인별로 분리했을때, 트랜잭션 처리의 한계와 대응 방안에 대한 설계 문서 제출&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-end=&quot;295&quot; data-start=&quot;260&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-end=&quot;278&quot; data-start=&quot;260&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/16&quot;&gt;Step15 PR&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-end=&quot;295&quot; data-start=&quot;279&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/17&quot;&gt;Step16 PR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1756643304744&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;Step15 by seuthootDev &amp;middot; Pull Request #16 &amp;middot; seuthootDev/hanghae-plus-backend&quot; data-og-description=&quot;  PR 제목 규칙 [STEP15] 정승훈 - (e-commerce) STEP 15 Application Event [✔️] 주문/예약 정보를 원 트랜잭션이 종료된 이후에 전송 [✔️] 주문/예약 정보를 전달하는 부가 로직에 대한 관심사를 메인 서&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/16&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/16&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cjvp12/hyZDVFhmQ2/yPHLRhCgpQDSQkU6dRMbG0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/mVa1t/hyZC0Uuti2/iNeDmRhLww8CChDYpNp3I1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/16&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/16&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cjvp12/hyZDVFhmQ2/yPHLRhCgpQDSQkU6dRMbG0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/mVa1t/hyZC0Uuti2/iNeDmRhLww8CChDYpNp3I1/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;Step15 by seuthootDev &amp;middot; Pull Request #16 &amp;middot; seuthootDev/hanghae-plus-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  PR 제목 규칙 [STEP15] 정승훈 - (e-commerce) STEP 15 Application Event [✔️] 주문/예약 정보를 원 트랜잭션이 종료된 이후에 전송 [✔️] 주문/예약 정보를 전달하는 부가 로직에 대한 관심사를 메인 서&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;figure id=&quot;og_1756643304129&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;Step16 by seuthootDev &amp;middot; Pull Request #17 &amp;middot; seuthootDev/hanghae-plus-backend&quot; data-og-description=&quot;  PR 제목 규칙 [STEP15] 정승훈 - (e-commerce) STEP 15 Application Event [✔️] 주문/예약 정보를 원 트랜잭션이 종료된 이후에 전송 [✔️] 주문/예약 정보를 전달하는 부가 로직에 대한 관심사를 메인 서&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/17&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/17&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iB5TV/hyZCZVBw94/R25SLs3gHZb87VtzfPuGKK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/2u1Kn/hyZGaBaiUA/MWBLavxls3OBZnpROS1DG1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/17&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iB5TV/hyZCZVBw94/R25SLs3gHZb87VtzfPuGKK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/2u1Kn/hyZGaBaiUA/MWBLavxls3OBZnpROS1DG1/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;Step16 by seuthootDev &amp;middot; Pull Request #17 &amp;middot; seuthootDev/hanghae-plus-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  PR 제목 규칙 [STEP15] 정승훈 - (e-commerce) STEP 15 Application Event [✔️] 주문/예약 정보를 원 트랜잭션이 종료된 이후에 전송 [✔️] 주문/예약 정보를 전달하는 부가 로직에 대한 관심사를 메인 서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;&lt;b&gt;항해 20만원 할인 추천인코드: NYFKU8&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;</description>
      <category>항해+</category>
      <category>DB</category>
      <category>낙관적락</category>
      <category>레디스</category>
      <category>부트캠프</category>
      <category>부트캠프할인</category>
      <category>분산락</category>
      <category>추천인코드</category>
      <category>할인</category>
      <category>항해추천인</category>
      <category>항해할인</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/10</guid>
      <comments>https://seuthootdev.tistory.com/10#entry10comment</comments>
      <pubDate>Sun, 31 Aug 2025 21:29:05 +0900</pubDate>
    </item>
    <item>
      <title>항해+ 백엔드 코드 7주차 회고 : Redis의 자료구조와 활용</title>
      <link>https://seuthootdev.tistory.com/9</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주 과제는 기존에 구현된 &lt;b&gt;선착순 쿠폰 발급&lt;/b&gt;과 &lt;b&gt;인기상품 조회&lt;/b&gt; 기능을 Redis의 자료구조를 활용하여 리팩토링하는 것이었습니다. 단순히 캐시로만 알고 있던 Redis가 사실은 &lt;b&gt;다양한 컬렉션 자료구조&lt;/b&gt;를 지원하고, 이를 통해 현업에서 랭킹 시스템, 이벤트 처리, 중복 제어 등 다양한 문제를 효율적으로 해결할 수 있다는 점을 새롭게 알게 되었습니다.&lt;/p&gt;
&lt;p data-end=&quot;511&quot; data-start=&quot;398&quot; data-ke-size=&quot;size16&quot;&gt;특히 Redis의 &lt;b&gt;Sorted Set&lt;/b&gt;은 굉장히 강력한 기능이라고 느꼈습니다. 원래는 직접 구현해야 하는 &lt;b&gt;실시간 랭킹 기능&lt;/b&gt;을 단 몇 개의 명령어로 처리할 수 있다는 점이 인상적이었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uggBP/btsP3b5RVUJ/UFKme0jYVsp7T3AycyOVv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uggBP/btsP3b5RVUJ/UFKme0jYVsp7T3AycyOVv0/img.png&quot; data-alt=&quot;레디스 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uggBP/btsP3b5RVUJ/UFKme0jYVsp7T3AycyOVv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuggBP%2FbtsP3b5RVUJ%2FUFKme0jYVsp7T3AycyOVv0%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;517&quot; height=&quot;300&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;레디스 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis 는 기본적으로 Key-Value 기반의 데이터 저장소입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Value 로는 단순히 String 뿐 아니라 &lt;b&gt;다양한 데이터 타입 ( Collections )&lt;/b&gt;를 지원하는데, 이를 활용해 현업에서 단순히 캐시 뿐 아니라 다양한 용도로 활용하고 있어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Strings&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반 문자열 ( 최대 512MB )&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단순 증감 연산&lt;/b&gt; 혹은 &lt;b&gt;문자열로 표현 가능한 모든 자료&lt;/b&gt; 저장하는 목적으로 활용&lt;/li&gt;
&lt;li&gt;주요 명령어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수정 계열 : set, setnx, ..&lt;/li&gt;
&lt;li&gt;조회 계열 : get, mget, ..&lt;/li&gt;
&lt;li&gt;INCR 계열 ( 단순 증감 )&lt;/li&gt;
&lt;/ul&gt;
&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img1.daumcdn.webp&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bP7p0I/btsP4Xeq9TM/A1qAtxHG0PfkJ0lyfor0gk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bP7p0I/btsP4Xeq9TM/A1qAtxHG0PfkJ0lyfor0gk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bP7p0I/btsP4Xeq9TM/A1qAtxHG0PfkJ0lyfor0gk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbP7p0I%2FbtsP4Xeq9TM%2FA1qAtxHG0PfkJ0lyfor0gk%2Fimg.webp&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;478&quot; height=&quot;122&quot; data-filename=&quot;img1.daumcdn.webp&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Sets&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장된 원소의 Unique 함을 보장하는 자료구조&lt;/li&gt;
&lt;li&gt;Set 은 정렬을 보장하지 않음&lt;/li&gt;
&lt;li&gt;Set 자료구조를 위한 연산 지원 ( 교집합 / 합집합 / 차집합 등 )&lt;/li&gt;
&lt;li&gt;주요 명령어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수정 계열 : sadd, smove&lt;/li&gt;
&lt;li&gt;조회 계열 : smembers, scard, ..&lt;/li&gt;
&lt;li&gt;제거 계열 : spop, srem&lt;/li&gt;
&lt;li&gt;집합 계열 : sunion, sinter, sdif, ..&lt;/li&gt;
&lt;/ul&gt;
&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img1.daumcdn (1).webp&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;457&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bomEVS/btsP4GRB0Wv/mecremxrAygmAiYooGkrT1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bomEVS/btsP4GRB0Wv/mecremxrAygmAiYooGkrT1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bomEVS/btsP4GRB0Wv/mecremxrAygmAiYooGkrT1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbomEVS%2FbtsP4GRB0Wv%2FmecremxrAygmAiYooGkrT1%2Fimg.webp&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;773&quot; height=&quot;457&quot; data-filename=&quot;img1.daumcdn (1).webp&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;457&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Sorted Sets&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;set + score 가중치 필드가 추가된 자료구조&lt;/li&gt;
&lt;li&gt;데이터 저장시, score 기반 오름차순 정렬로 저장됨&lt;/li&gt;
&lt;li&gt;score 값이 같은 경우, 사전순으로 정렬&lt;/li&gt;
&lt;li&gt;주요 명령어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수정 계열 : ZADD&lt;/li&gt;
&lt;li&gt;조회 계열 : ZRANGE, ZRANGEBYSCORE, ZRANK, ZSCORE, ..&lt;/li&gt;
&lt;li&gt;제거 계열 : ZPOPMIN, ZPOPMAX, ZREM, ..&lt;/li&gt;
&lt;li&gt;증감 계열 : ZINCRBY&lt;/li&gt;
&lt;li&gt;집합 계열 : ZUNIONSTORE, ZINTERSTORE&lt;/li&gt;
&lt;/ul&gt;
&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img1.daumcdn (2).webp&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bG23zt/btsP5FEh4Pl/aFA7HLVdRgbYm42c5XddXK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bG23zt/btsP5FEh4Pl/aFA7HLVdRgbYm42c5XddXK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bG23zt/btsP5FEh4Pl/aFA7HLVdRgbYm42c5XddXK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbG23zt%2FbtsP5FEh4Pl%2FaFA7HLVdRgbYm42c5XddXK%2Fimg.webp&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;768&quot; height=&quot;589&quot; data-filename=&quot;img1.daumcdn (2).webp&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Redis 기반의 랭킹 시스템&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  개요&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실시간 랭킹이 필요한 시스템(게임 점수, 인기 콘텐츠, 상품 조회 등)에 적합&lt;/li&gt;
&lt;li&gt;Redis의&amp;nbsp;Sorted Set을 활용하여 효율적이고 빠른 랭킹 처리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  핵심 개념: Redis Sorted Set&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조:&amp;nbsp;ZADD key score member&lt;/li&gt;
&lt;li&gt;정렬: score 기준 오름차순 (낮은 점수 &amp;rarr; 높은 점수)&lt;/li&gt;
&lt;li&gt;특징:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 점수면 사전순 정렬&lt;/li&gt;
&lt;li&gt;점수 기반으로 순위 계산이 가능함&lt;/li&gt;
&lt;li&gt;조회 및 수정이 매우 빠름 (O(log N))&lt;/li&gt;
&lt;/ul&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;  기본 명령어 예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 점수 추가 및 갱신&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;ZADD game_ranking 1500 user123
ZADD game_ranking 3000 user456
ZADD game_ranking 2500 user789
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 특정 사용자 점수 조회&lt;/h3&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;ZSCORE game_ranking user123
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 전체 랭킹 조회 (높은 점수가 1등)&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;ZREVRANGE game_ranking 0 9 WITHSCORES  # Top 10
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 특정 사용자 순위 조회&lt;/h3&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;ZREVRANK game_ranking user123
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 점수 증가 (예: 게임 승리 시 점수 부여)&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;ZINCRBY game_ranking 100 user123
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  응용 예시: 일간 / 주간 랭킹 분리&lt;/h2&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;ranking:daily:20240429&lt;/li&gt;
&lt;li&gt;ranking:weekly:2024-W18&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TTL 설정&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일간 랭킹은 하루 후 자동 만료&lt;/li&gt;
&lt;li&gt;주간 랭킹은 일주일 후 만료&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;EXPIRE ranking:daily:20240429 86400
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⚠️ 주의할 점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Sorted Set에 너무 많은 데이터를 넣으면 메모리 부담 &amp;uarr;&lt;/li&gt;
&lt;li&gt;TTL 없이 데이터 계속 쌓이면 만료 누락 가능성 존재&lt;/li&gt;
&lt;li&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;  실전 활용 예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인기 상품 조회 랭킹 (24시간 클릭 수 기준)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ZINCRBY product:ranking:clicks:20240429 1 product123&lt;/li&gt;
&lt;li&gt;매일 자정 배치로 새로운 키 생성 및 TTL 부여&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;ZADD game:ranking:user 5000 userA&lt;/li&gt;
&lt;li&gt;클라이언트에게&amp;nbsp;ZREVRANK&amp;nbsp;결과 전달하여 등수 노출&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  시각화 전략&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redis에서 Top N을 가져와 DB 캐싱 &amp;rarr; 사용자에게 제공&lt;/li&gt;
&lt;li&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;✅ 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능 Redis 명령어&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;점수 등록/수정&lt;/td&gt;
&lt;td&gt;ZADD, ZINCRBY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;순위 조회&lt;/td&gt;
&lt;td&gt;ZREVRANK, ZREVRANGE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;점수 조회&lt;/td&gt;
&lt;td&gt;ZSCORE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 만료&lt;/td&gt;
&lt;td&gt;EXPIRE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redis 공식 문서:&amp;nbsp;&lt;a href=&quot;https://redis.io/commands/zadd/&quot;&gt;https://redis.io/commands/zadd/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis TTL 관리:&amp;nbsp;&lt;a href=&quot;https://redis.io/docs/manual/key-expiration/&quot;&gt;https://redis.io/docs/manual/key-expiration/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;과제&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;260&quot; data-end=&quot;295&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-start=&quot;260&quot; data-end=&quot;278&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/13&quot;&gt;Step13 PR&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-start=&quot;279&quot; data-end=&quot;295&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/14&quot;&gt;Step14 PR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1756085039955&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;Step14 by seuthootDev &amp;middot; Pull Request #14 &amp;middot; seuthootDev/hanghae-plus-backend&quot; data-og-description=&quot;  PR 제목 규칙 [STEP14] 정승훈 - (e-commerce) 핵심 체크리스트 ✅ one: ranking design [✔] 적절한 설계를 기반으로 랭킹기능이 개발되었는가? [✔] 적절한 자료구조를 선택하였는가? 05c2b9c f625a44 8590803 67&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/14&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/14&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XPuc4/hyZCYnMEoQ/npWCJvoW33jqOdiRVd5QjK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/vRWv1/hyZC60pozM/TVYTW1cwUQXnely9Kh1vOk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/14&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/14&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XPuc4/hyZCYnMEoQ/npWCJvoW33jqOdiRVd5QjK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/vRWv1/hyZC60pozM/TVYTW1cwUQXnely9Kh1vOk/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;Step14 by seuthootDev &amp;middot; Pull Request #14 &amp;middot; seuthootDev/hanghae-plus-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  PR 제목 규칙 [STEP14] 정승훈 - (e-commerce) 핵심 체크리스트 ✅ one: ranking design [✔] 적절한 설계를 기반으로 랭킹기능이 개발되었는가? [✔] 적절한 자료구조를 선택하였는가? 05c2b9c f625a44 8590803 67&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과제는 다음과 같은 방식으로 구현했습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;874&quot; data-start=&quot;544&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;639&quot; data-start=&quot;544&quot;&gt;&lt;b&gt;선착순 쿠폰 발급 기능&lt;/b&gt;은 사용자 요청이 발생하면 &lt;b&gt;Sorted Set으로 순위를 기록&lt;/b&gt;하고, 그 결과를 기반으로 실제 DB에 쿠폰을 발급하도록 했습니다.&lt;/li&gt;
&lt;li data-end=&quot;786&quot; data-start=&quot;640&quot;&gt;단, 랭킹 기록 이후 DB 저장 직전에 장애가 발생할 수 있다는 리스크가 있어, &lt;b&gt;랭킹 기록과 로그 저장을 비동기적으로 처리&lt;/b&gt;하도록 설계했습니다. 이렇게 함으로써 장애 상황에서도 최소한 발급 순위 정보는 Redis에 안전하게 남길 수 있도록 했습니다.&lt;/li&gt;
&lt;li data-end=&quot;874&quot; data-start=&quot;787&quot;&gt;또한, 인기 상품 조회 기능 역시 &lt;b&gt;클릭 수를 Sorted Set에 누적&lt;/b&gt;하는 방식으로 구현해, 실시간으로 상품의 인기도를 반영할 수 있었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 과제를 통해 Redis가 단순 캐시 도구를 넘어 &lt;b&gt;데이터를 구조적으로 다루고 실시간성을 보장하는 핵심 인프라&lt;/b&gt;가 될 수 있음을 체감했습니다. 앞으로도 이런 자료구조적 특성을 잘 이해하고 활용하면, 더 많은 비즈니스 로직을 단순화하면서도 성능을 확보할 수 있을 것 같습니다.&lt;/p&gt;</description>
      <category>항해+</category>
      <category>DB</category>
      <category>낙관적락</category>
      <category>레디스</category>
      <category>부트캠프</category>
      <category>부트캠프할인</category>
      <category>분산락</category>
      <category>추천인코드</category>
      <category>할인</category>
      <category>항해추천인</category>
      <category>항해할인</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/9</guid>
      <comments>https://seuthootdev.tistory.com/9#entry9comment</comments>
      <pubDate>Mon, 25 Aug 2025 10:24:17 +0900</pubDate>
    </item>
    <item>
      <title>항해+ 백엔드 코드 6주차 회고 : 분산락 + 캐시</title>
      <link>https://seuthootdev.tistory.com/8</link>
      <description>&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ovdJ1/btsPUgGotEn/HGGWCdG0hLWBBjEKi1ksyk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ovdJ1/btsPUgGotEn/HGGWCdG0hLWBBjEKi1ksyk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ovdJ1/btsPUgGotEn/HGGWCdG0hLWBBjEKi1ksyk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FovdJ1%2FbtsPUgGotEn%2FHGGWCdG0hLWBBjEKi1ksyk%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;1600&quot; height=&quot;800&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;&lt;i&gt;&lt;u&gt;&lt;b&gt;항해 20만원 할인 추천인코드: NYFKU8&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-start=&quot;243&quot; data-end=&quot;246&quot; /&gt;
&lt;h1 data-end=&quot;98&quot; data-start=&quot;82&quot;&gt;  분산락 &amp;amp; 캐시 정리&lt;/h1&gt;
&lt;h2 data-end=&quot;113&quot; data-start=&quot;100&quot; data-ke-size=&quot;size26&quot;&gt;1. 왜 필요한가?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;244&quot; data-start=&quot;114&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;180&quot; data-start=&quot;114&quot;&gt;대용량 트래픽 환경에서는 **한정된 자원(쿠폰, 좌석, 재고 등)**에 동시에 접근하는 문제가 자주 발생합니다.&lt;/li&gt;
&lt;li data-end=&quot;244&quot; data-start=&quot;181&quot;&gt;단순히 DB 트랜잭션만으로는 성능 한계가 있어 &lt;b&gt;Redis 기반 분산락 + 캐시 전략&lt;/b&gt;이 효과적입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;249&quot; data-start=&quot;246&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;269&quot; data-start=&quot;251&quot; data-ke-size=&quot;size26&quot;&gt;2. Redis 기반 분산락&lt;/h2&gt;
&lt;p data-end=&quot;329&quot; data-start=&quot;270&quot; data-ke-size=&quot;size16&quot;&gt;Redis는 Key-Value 저장소이자 원자적 연산을 지원하기 때문에, &lt;b&gt;락 관리&lt;/b&gt;에 적합합니다.&lt;/p&gt;
&lt;h3 data-end=&quot;340&quot; data-start=&quot;331&quot; data-ke-size=&quot;size23&quot;&gt;동작 방식&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;468&quot; data-start=&quot;341&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;387&quot; data-start=&quot;341&quot;&gt;&lt;b&gt;락 획득&lt;/b&gt;: SETNX key value 로 키가 없을 때만 등록&lt;/li&gt;
&lt;li data-end=&quot;407&quot; data-start=&quot;388&quot;&gt;&lt;b&gt;비즈니스 로직 수행&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;437&quot; data-start=&quot;408&quot;&gt;&lt;b&gt;락 해제&lt;/b&gt;: DEL key 로 해제&lt;/li&gt;
&lt;li data-end=&quot;468&quot; data-start=&quot;438&quot;&gt;&lt;b&gt;TTL 설정&lt;/b&gt;: 장애 시 자동 해제 보장&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-end=&quot;479&quot; data-start=&quot;470&quot; data-ke-size=&quot;size23&quot;&gt;구현 방식&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;759&quot; data-start=&quot;480&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;554&quot; data-start=&quot;480&quot;&gt;&lt;b&gt;Simple Lock&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;554&quot; data-start=&quot;502&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;528&quot; data-start=&quot;502&quot;&gt;실패 즉시 예외 발생 &amp;rarr; 빠른 실패 처리&lt;/li&gt;
&lt;li data-end=&quot;554&quot; data-start=&quot;531&quot;&gt;단점: 재시도 로직 별도 구현 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;651&quot; data-start=&quot;555&quot;&gt;&lt;b&gt;Spin Lock&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;651&quot; data-start=&quot;575&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;599&quot; data-start=&quot;575&quot;&gt;실패 시 일정 횟수/시간 동안 재시도&lt;/li&gt;
&lt;li data-end=&quot;621&quot; data-start=&quot;602&quot;&gt;장점: 결국 락 획득 확률&amp;uarr;&lt;/li&gt;
&lt;li data-end=&quot;651&quot; data-start=&quot;624&quot;&gt;단점: 네트워크 비용 &amp;amp; 스레드 점유 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;759&quot; data-start=&quot;652&quot;&gt;&lt;b&gt;Pub/Sub Lock&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;759&quot; data-start=&quot;675&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;714&quot; data-start=&quot;675&quot;&gt;Redis Pub/Sub 활용 &amp;rarr; 락 해제 이벤트 구독 후 대기&lt;/li&gt;
&lt;li data-end=&quot;741&quot; data-start=&quot;717&quot;&gt;장점: Spin Lock 대비 효율적&lt;/li&gt;
&lt;li data-end=&quot;759&quot; data-start=&quot;744&quot;&gt;단점: 구현 난이도&amp;uarr;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;771&quot; data-start=&quot;761&quot; data-ke-size=&quot;size23&quot;&gt;올바른 순서&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;락 획득 &amp;rarr; 트랜잭션 시작 &amp;rarr; 로직 실행 &amp;rarr; 트랜잭션 종료 &amp;rarr; 락 해제 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;864&quot; data-start=&quot;820&quot; data-ke-size=&quot;size16&quot;&gt;잘못된 순서(트랜잭션 먼저 시작 / 락 먼저 해제)는 데이터 정합성 깨뜨림.&lt;/p&gt;
&lt;hr data-end=&quot;869&quot; data-start=&quot;866&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;889&quot; data-start=&quot;871&quot; data-ke-size=&quot;size26&quot;&gt;3. 캐시(Cache) 활용&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1038&quot; data-start=&quot;890&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;932&quot; data-start=&quot;890&quot;&gt;Redis는 단순 캐시뿐만 아니라 &lt;b&gt;분산락 인프라&lt;/b&gt; 역할도 수행.&lt;/li&gt;
&lt;li data-end=&quot;1038&quot; data-start=&quot;933&quot;&gt;&lt;b&gt;캐시 장점&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1038&quot; data-start=&quot;947&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;979&quot; data-start=&quot;947&quot;&gt;DB 부하 감소 &amp;rarr; 성능(Throughput) 향상&lt;/li&gt;
&lt;li data-end=&quot;1005&quot; data-start=&quot;982&quot;&gt;TTL 활용 &amp;rarr; 데이터 최신성 보장&lt;/li&gt;
&lt;li data-end=&quot;1038&quot; data-start=&quot;1008&quot;&gt;락과 함께 &amp;rarr; &lt;b&gt;정합성 + 성능 동시 달성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1043&quot; data-start=&quot;1040&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1053&quot; data-start=&quot;1045&quot; data-ke-size=&quot;size26&quot;&gt;4. 정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1212&quot; data-start=&quot;1054&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1088&quot; data-start=&quot;1054&quot;&gt;&lt;b&gt;분산락&lt;/b&gt;: 데이터 정합성을 지키기 위한 핵심 기술&lt;/li&gt;
&lt;li data-end=&quot;1115&quot; data-start=&quot;1089&quot;&gt;&lt;b&gt;캐시&lt;/b&gt;: 성능 최적화 및 부하 분산&lt;/li&gt;
&lt;li data-end=&quot;1144&quot; data-start=&quot;1116&quot;&gt;Redis는 두 역할을 모두 수행할 수 있음&lt;/li&gt;
&lt;li data-end=&quot;1212&quot; data-start=&quot;1145&quot;&gt;결국, 대규모 트래픽 환경에서는&lt;br /&gt;  &lt;b&gt;Redis 분산락 + 캐시 전략&lt;/b&gt;이 안정적인 서비스 운영의 핵심&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;259&quot; data-start=&quot;248&quot; data-ke-size=&quot;size26&quot;&gt;  과제 링크&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-end=&quot;295&quot; data-start=&quot;260&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-end=&quot;278&quot; data-start=&quot;260&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/11&quot;&gt;Step11 PR&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-end=&quot;295&quot; data-start=&quot;279&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/12&quot;&gt;Step12 PR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1755515609647&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;Step12 by seuthootDev &amp;middot; Pull Request #12 &amp;middot; seuthootDev/hanghae-plus-backend&quot; data-og-description=&quot;  PR 제목 규칙 [STEP12] 정승훈 - e-commerce 핵심 체크리스트 ✅ 1️⃣ 분산락 적용 (3개) [✔️] 적절한 곳에 분산락이 사용되었는가? 79a61a7 0f4c3c0 [✔️] 트랜젝션 순서와 락순서가 보장되었는가? ae2&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/12&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/12&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/7R8kf/hyZC6rr43L/aUBDg3WlmRLBHwvaSFIb70/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/c67bHM/hyZzIZxEHs/NnJtKNUokxnjmtna9nWcQ0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/12&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/7R8kf/hyZC6rr43L/aUBDg3WlmRLBHwvaSFIb70/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/c67bHM/hyZzIZxEHs/NnJtKNUokxnjmtna9nWcQ0/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;Step12 by seuthootDev &amp;middot; Pull Request #12 &amp;middot; seuthootDev/hanghae-plus-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  PR 제목 규칙 [STEP12] 정승훈 - e-commerce 핵심 체크리스트 ✅ 1️⃣ 분산락 적용 (3개) [✔️] 적절한 곳에 분산락이 사용되었는가? 79a61a7 0f4c3c0 [✔️] 트랜젝션 순서와 락순서가 보장되었는가? ae2&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;figure id=&quot;og_1755515609237&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;Step11 by seuthootDev &amp;middot; Pull Request #11 &amp;middot; seuthootDev/hanghae-plus-backend&quot; data-og-description=&quot;  PR 제목 규칙 [STEP11] 정승훈 - e-commerce 핵심 체크리스트 ✅ 1️⃣ 분산락 적용 (3개) [✔️] 적절한 곳에 분산락이 사용되었는가? 79a61a7 0f4c3c0 [✔️] 트랜젝션 순서와 락순서가 보장되었는가? ae2&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/11&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/11&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/0e03G/hyZCXgYeR1/y30bW75KSr6VMCKkyWFeCK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/cprJhG/hyZzyo4aUm/taB9pQdKK5f7FtVkykMkW0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/11&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/11&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/0e03G/hyZCXgYeR1/y30bW75KSr6VMCKkyWFeCK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/cprJhG/hyZzyo4aUm/taB9pQdKK5f7FtVkykMkW0/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;Step11 by seuthootDev &amp;middot; Pull Request #11 &amp;middot; seuthootDev/hanghae-plus-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  PR 제목 규칙 [STEP11] 정승훈 - e-commerce 핵심 체크리스트 ✅ 1️⃣ 분산락 적용 (3개) [✔️] 적절한 곳에 분산락이 사용되었는가? 79a61a7 0f4c3c0 [✔️] 트랜젝션 순서와 락순서가 보장되었는가? ae2&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;</description>
      <category>항해+</category>
      <category>DB</category>
      <category>낙관적락</category>
      <category>레디스</category>
      <category>부트캠프</category>
      <category>부트캠프할인</category>
      <category>분산락</category>
      <category>추천인코드</category>
      <category>할인</category>
      <category>항해추천인</category>
      <category>항해할인</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/8</guid>
      <comments>https://seuthootdev.tistory.com/8#entry8comment</comments>
      <pubDate>Mon, 18 Aug 2025 20:14:04 +0900</pubDate>
    </item>
    <item>
      <title>항해+ 백엔드 코드 5주차 회고 : 동시성 처리(Concurrency Control) 과제 정리 &amp;ndash; 데이터 정합성과 성능 동시 확보하기 (항해 부트캠프 할인코드 있음)</title>
      <link>https://seuthootdev.tistory.com/7</link>
      <description>&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgivTd/btsPNlGswqM/xkQQmMaW100oW1W61LG25K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgivTd/btsPNlGswqM/xkQQmMaW100oW1W61LG25K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgivTd/btsPNlGswqM/xkQQmMaW100oW1W61LG25K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgivTd%2FbtsPNlGswqM%2FxkQQmMaW100oW1W61LG25K%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;1600&quot; height=&quot;800&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;이번 주차의 메인 주제는 동시성 처리 였습니다.&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;&lt;i&gt;&lt;u&gt;&lt;b&gt;항해 20만원 할인 추천인코드: NYFKU8&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-end=&quot;246&quot; data-start=&quot;243&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;375&quot; data-start=&quot;178&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요!&lt;/p&gt;
&lt;p data-end=&quot;375&quot; data-start=&quot;178&quot; data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 제가 진행한 &lt;b&gt;동시성 처리(Concurrency Control)&lt;/b&gt; 과제에 대해 정리해보려고 합니다.&lt;br /&gt;실제 서비스 환경에서 자주 발생하는 경쟁 상황에서도 데이터 정합성을 지키면서 동시에 높은 성능을 내는 것이 목표였는데요,&lt;br /&gt;제가 어떤 전략을 선택했고 어떻게 구현했는지, 그리고 검증 결과까지 자세히 공유합니다.&lt;/p&gt;
&lt;hr data-end=&quot;380&quot; data-start=&quot;377&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;389&quot; data-start=&quot;382&quot; data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;525&quot; data-start=&quot;390&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;405&quot; data-start=&quot;390&quot;&gt;과제 개요 및 목표&lt;/li&gt;
&lt;li data-end=&quot;423&quot; data-start=&quot;406&quot;&gt;동시성 관련 기본 개념&lt;/li&gt;
&lt;li data-end=&quot;442&quot; data-start=&quot;424&quot;&gt;전략 선택과 도메인 매핑&lt;/li&gt;
&lt;li data-end=&quot;459&quot; data-start=&quot;443&quot;&gt;3계층 락 구현 방식&lt;/li&gt;
&lt;li data-end=&quot;479&quot; data-start=&quot;460&quot;&gt;주요 코드 및 테스트 결과&lt;/li&gt;
&lt;li data-end=&quot;495&quot; data-start=&quot;480&quot;&gt;성능 측정 및 결과&lt;/li&gt;
&lt;li data-end=&quot;513&quot; data-start=&quot;496&quot;&gt;전략 타당성 및 한계점&lt;/li&gt;
&lt;li data-end=&quot;525&quot; data-start=&quot;514&quot;&gt;마무리 요약&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;530&quot; data-start=&quot;527&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;548&quot; data-start=&quot;532&quot; data-ke-size=&quot;size26&quot;&gt;1. 과제 개요 및 목표&lt;/h2&gt;
&lt;p data-end=&quot;719&quot; data-start=&quot;550&quot; data-ke-size=&quot;size16&quot;&gt;이번 과제의 주제는 바로 &lt;b&gt;동시성 처리&lt;/b&gt; 입니다.&lt;br /&gt;서비스가 커지고 여러 사용자가 동시에 요청할 때, 발생할 수 있는 데이터 충돌 문제를 방지하는 것이 핵심입니다.&lt;br /&gt;목표는 경쟁 상황에서도 &lt;b&gt;데이터 정합성(Consistency)&lt;/b&gt; 을 보장하고, 동시에 &lt;b&gt;성능&lt;/b&gt; 저하를 최소화하는 것입니다.&lt;/p&gt;
&lt;hr data-end=&quot;724&quot; data-start=&quot;721&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;744&quot; data-start=&quot;726&quot; data-ke-size=&quot;size26&quot;&gt;2. 동시성 관련 기본 개념&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1200&quot; data-start=&quot;746&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;968&quot; data-start=&quot;746&quot;&gt;&lt;b&gt;트랜잭션과 ACID&lt;/b&gt;&lt;br /&gt;데이터 정합성을 보장하기 위해 트랜잭션은 반드시 ACID 원칙을 따라야 합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;968&quot; data-start=&quot;816&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;851&quot; data-start=&quot;816&quot;&gt;Atomicity (원자성): 모두 성공하거나 모두 실패&lt;/li&gt;
&lt;li data-end=&quot;887&quot; data-start=&quot;854&quot;&gt;Consistency (일관성): 데이터 일관성 유지&lt;/li&gt;
&lt;li data-end=&quot;923&quot; data-start=&quot;890&quot;&gt;Isolation (고립성): 트랜잭션 간 간섭 방지&lt;/li&gt;
&lt;li data-end=&quot;965&quot; data-start=&quot;926&quot;&gt;Durability (지속성): 완료된 트랜잭션 결과 영구 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1102&quot; data-start=&quot;969&quot;&gt;&lt;b&gt;격리 수준 (Isolation Level)&lt;/b&gt;&lt;br /&gt;성능과 안정성 사이 균형을 위해 보통 아래 중 선택합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1102&quot; data-start=&quot;1040&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1058&quot; data-start=&quot;1040&quot;&gt;Read Committed&lt;/li&gt;
&lt;li data-end=&quot;1080&quot; data-start=&quot;1061&quot;&gt;Repeatable Read&lt;/li&gt;
&lt;li data-end=&quot;1099&quot; data-start=&quot;1083&quot;&gt;Serializable&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1200&quot; data-start=&quot;1103&quot;&gt;&lt;b&gt;동시성 문제 유형&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1200&quot; data-start=&quot;1123&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1138&quot; data-start=&quot;1123&quot;&gt;Lost Update&lt;/li&gt;
&lt;li data-end=&quot;1155&quot; data-start=&quot;1141&quot;&gt;Dirty Read&lt;/li&gt;
&lt;li data-end=&quot;1181&quot; data-start=&quot;1158&quot;&gt;Non-Repeatable Read&lt;/li&gt;
&lt;li data-end=&quot;1200&quot; data-start=&quot;1184&quot;&gt;Phantom Read&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1205&quot; data-start=&quot;1202&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1226&quot; data-start=&quot;1207&quot; data-ke-size=&quot;size26&quot;&gt;3. 전략 선택과 도메인 매핑&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1567&quot; data-start=&quot;1228&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1341&quot; data-start=&quot;1228&quot;&gt;&lt;b&gt;락 전략&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1341&quot; data-start=&quot;1243&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1292&quot; data-start=&quot;1243&quot;&gt;&lt;b&gt;비관적 락&lt;/b&gt;: 충돌을 미리 방지하기 위해 선잠금, 안정적이지만 성능 부담 큼&lt;/li&gt;
&lt;li data-end=&quot;1338&quot; data-start=&quot;1295&quot;&gt;&lt;b&gt;낙관적 락&lt;/b&gt;: 버전 비교 후 재시도 방식, 충돌 적으면 성능 우수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1567&quot; data-start=&quot;1342&quot;&gt;&lt;b&gt;도메인별 전략 선택 기준&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;도메인충돌 빈도중요도락 전략
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1567&quot; data-start=&quot;1366&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1567&quot; data-start=&quot;1429&quot;&gt;
&lt;tr data-end=&quot;1476&quot; data-start=&quot;1429&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1446&quot; data-start=&quot;1429&quot;&gt;쿠폰 발급 (선착순 보장)&lt;/td&gt;
&lt;td data-end=&quot;1451&quot; data-start=&quot;1446&quot; data-col-size=&quot;sm&quot;&gt;높음&lt;/td&gt;
&lt;td data-end=&quot;1465&quot; data-start=&quot;1451&quot; data-col-size=&quot;sm&quot;&gt;순서/수량 보장 필수&lt;/td&gt;
&lt;td data-end=&quot;1476&quot; data-start=&quot;1465&quot; data-col-size=&quot;sm&quot;&gt;비관적 락&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1515&quot; data-start=&quot;1479&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1491&quot; data-start=&quot;1479&quot;&gt;포인트 충전/차감&lt;/td&gt;
&lt;td data-end=&quot;1496&quot; data-start=&quot;1491&quot; data-col-size=&quot;sm&quot;&gt;중간&lt;/td&gt;
&lt;td data-end=&quot;1504&quot; data-start=&quot;1496&quot; data-col-size=&quot;sm&quot;&gt;성능 중요&lt;/td&gt;
&lt;td data-end=&quot;1515&quot; data-start=&quot;1504&quot; data-col-size=&quot;sm&quot;&gt;낙관적 락&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1567&quot; data-start=&quot;1518&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1536&quot; data-start=&quot;1518&quot;&gt;주문 생성, 회원가입, 결제&lt;/td&gt;
&lt;td data-end=&quot;1541&quot; data-start=&quot;1536&quot; data-col-size=&quot;sm&quot;&gt;중간&lt;/td&gt;
&lt;td data-end=&quot;1556&quot; data-start=&quot;1541&quot; data-col-size=&quot;sm&quot;&gt;성능 + 재시도 용이성&lt;/td&gt;
&lt;td data-end=&quot;1567&quot; data-start=&quot;1556&quot; data-col-size=&quot;sm&quot;&gt;낙관적 락&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1572&quot; data-start=&quot;1569&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1591&quot; data-start=&quot;1574&quot; data-ke-size=&quot;size26&quot;&gt;4. 3계층 락 구현 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1842&quot; data-start=&quot;1593&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1675&quot; data-start=&quot;1593&quot;&gt;&lt;b&gt;애플리케이션 레벨 락&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1675&quot; data-start=&quot;1615&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1672&quot; data-start=&quot;1615&quot;&gt;@OptimisticLock, @PessimisticLock 데코레이터와 인터셉터로 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1766&quot; data-start=&quot;1676&quot;&gt;&lt;b&gt;Redis 분산 락&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1766&quot; data-start=&quot;1697&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1723&quot; data-start=&quot;1697&quot;&gt;다중 서버 환경에서의 동시성 이슈 방지용&lt;/li&gt;
&lt;li data-end=&quot;1763&quot; data-start=&quot;1726&quot;&gt;RedisPessimisticLockInterceptor&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1842&quot; data-start=&quot;1767&quot;&gt;&lt;b&gt;DB 물리적 락(보조적 사용)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1842&quot; data-start=&quot;1794&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1817&quot; data-start=&quot;1794&quot;&gt;FOR UPDATE 행 단위 락&lt;/li&gt;
&lt;li data-end=&quot;1839&quot; data-start=&quot;1820&quot;&gt;낙관적 락용 버전 컬럼 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1846&quot; data-start=&quot;1843&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1868&quot; data-start=&quot;1848&quot; data-ke-size=&quot;size26&quot;&gt;5. 주요 코드 위치 및 테스트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2098&quot; data-start=&quot;1870&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1949&quot; data-start=&quot;1870&quot;&gt;데코레이터 &amp;amp; 인터셉터:&lt;br /&gt;src/common/decorators/*&lt;br /&gt;src/common/interceptors/*&lt;/li&gt;
&lt;li data-end=&quot;2020&quot; data-start=&quot;1953&quot;&gt;레포지토리 적용:&lt;br /&gt;src/infrastructure/repositories/*.repository.ts&lt;/li&gt;
&lt;li data-end=&quot;2095&quot; data-start=&quot;2024&quot;&gt;테스트:&lt;br /&gt;test/it/integration/concurrency.integration.spec.ts 외 다수&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2102&quot; data-start=&quot;2099&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2120&quot; data-start=&quot;2104&quot; data-ke-size=&quot;size26&quot;&gt;6. 검증 및 성능 결과&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2740&quot; data-start=&quot;2122&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2150&quot; data-start=&quot;2122&quot;&gt;&lt;b&gt;통합 테스트&lt;/b&gt; 59개 항목 모두 통과!&lt;/li&gt;
&lt;li data-end=&quot;2360&quot; data-start=&quot;2151&quot;&gt;핵심 시나리오 검증 결과:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2360&quot; data-start=&quot;2172&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2213&quot; data-start=&quot;2172&quot;&gt;동시 포인트 충전(10건) &amp;rarr; 모두 성공 (낙관적 락 재시도 포함)&lt;/li&gt;
&lt;li data-end=&quot;2252&quot; data-start=&quot;2216&quot;&gt;동시 주문 생성(5건) &amp;rarr; 재고 및 쿠폰 일관성 보장 성공&lt;/li&gt;
&lt;li data-end=&quot;2296&quot; data-start=&quot;2255&quot;&gt;중복 결제 방지 &amp;rarr; 1건 성공, 2건 실패 (중복 차단 정상 작동)&lt;/li&gt;
&lt;li data-end=&quot;2332&quot; data-start=&quot;2299&quot;&gt;동시 쿠폰 발급(5건) &amp;rarr; 선착순 순서 및 수량 보존&lt;/li&gt;
&lt;li data-end=&quot;2357&quot; data-start=&quot;2335&quot;&gt;트랜잭션 롤백 시 잔액 정상 복구&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2737&quot; data-start=&quot;2361&quot;&gt;&lt;b&gt;성능 측정 요약&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;작업요청수평균 처리 시간TPS(초당 처리량)
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2737&quot; data-start=&quot;2380&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;2737&quot; data-start=&quot;2444&quot;&gt;
&lt;tr data-end=&quot;2489&quot; data-start=&quot;2444&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2459&quot; data-start=&quot;2444&quot;&gt;포인트 충전 (10건)&lt;/td&gt;
&lt;td data-end=&quot;2464&quot; data-start=&quot;2459&quot; data-col-size=&quot;sm&quot;&gt;10&lt;/td&gt;
&lt;td data-end=&quot;2474&quot; data-start=&quot;2464&quot; data-col-size=&quot;sm&quot;&gt;57.4 ms&lt;/td&gt;
&lt;td data-end=&quot;2489&quot; data-start=&quot;2474&quot; data-col-size=&quot;sm&quot;&gt;174 req/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2535&quot; data-start=&quot;2492&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2505&quot; data-start=&quot;2492&quot;&gt;주문 생성 (5건)&lt;/td&gt;
&lt;td data-end=&quot;2509&quot; data-start=&quot;2505&quot; data-col-size=&quot;sm&quot;&gt;5&lt;/td&gt;
&lt;td data-end=&quot;2520&quot; data-start=&quot;2509&quot; data-col-size=&quot;sm&quot;&gt;32.49 ms&lt;/td&gt;
&lt;td data-end=&quot;2535&quot; data-start=&quot;2520&quot; data-col-size=&quot;sm&quot;&gt;154 req/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2578&quot; data-start=&quot;2538&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2548&quot; data-start=&quot;2538&quot;&gt;결제 (3건)&lt;/td&gt;
&lt;td data-end=&quot;2552&quot; data-start=&quot;2548&quot; data-col-size=&quot;sm&quot;&gt;3&lt;/td&gt;
&lt;td data-end=&quot;2563&quot; data-start=&quot;2552&quot; data-col-size=&quot;sm&quot;&gt;19.47 ms&lt;/td&gt;
&lt;td data-end=&quot;2578&quot; data-start=&quot;2563&quot; data-col-size=&quot;sm&quot;&gt;154 req/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2624&quot; data-start=&quot;2581&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2594&quot; data-start=&quot;2581&quot;&gt;쿠폰 발급 (5건)&lt;/td&gt;
&lt;td data-end=&quot;2598&quot; data-start=&quot;2594&quot; data-col-size=&quot;sm&quot;&gt;5&lt;/td&gt;
&lt;td data-end=&quot;2609&quot; data-start=&quot;2598&quot; data-col-size=&quot;sm&quot;&gt;28.11 ms&lt;/td&gt;
&lt;td data-end=&quot;2624&quot; data-start=&quot;2609&quot; data-col-size=&quot;sm&quot;&gt;178 req/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2673&quot; data-start=&quot;2627&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2644&quot; data-start=&quot;2627&quot;&gt;선착순 쿠폰 (3건 순차)&lt;/td&gt;
&lt;td data-end=&quot;2648&quot; data-start=&quot;2644&quot; data-col-size=&quot;sm&quot;&gt;3&lt;/td&gt;
&lt;td data-end=&quot;2658&quot; data-start=&quot;2648&quot; data-col-size=&quot;sm&quot;&gt;7.92 ms&lt;/td&gt;
&lt;td data-end=&quot;2673&quot; data-start=&quot;2658&quot; data-col-size=&quot;sm&quot;&gt;379 req/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2737&quot; data-start=&quot;2676&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2702&quot; data-start=&quot;2676&quot;&gt;대량 처리 (포인트20/주문10/쿠폰15)&lt;/td&gt;
&lt;td data-end=&quot;2707&quot; data-start=&quot;2702&quot; data-col-size=&quot;sm&quot;&gt;45&lt;/td&gt;
&lt;td data-end=&quot;2718&quot; data-start=&quot;2707&quot; data-col-size=&quot;sm&quot;&gt;53~63 ms&lt;/td&gt;
&lt;td data-end=&quot;2737&quot; data-start=&quot;2718&quot; data-col-size=&quot;sm&quot;&gt;159~318 req/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2744&quot; data-start=&quot;2741&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2765&quot; data-start=&quot;2746&quot; data-ke-size=&quot;size26&quot;&gt;7. 왜 이 전략이 타당한가?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3001&quot; data-start=&quot;2767&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2835&quot; data-start=&quot;2767&quot;&gt;쿠폰은 &lt;b&gt;정확한 순서와 수량 보장&lt;/b&gt;이 비즈니스 핵심이므로,&lt;br /&gt;충돌을 즉시 제거하는 비관적 락이 적합합니다.&lt;/li&gt;
&lt;li data-end=&quot;2916&quot; data-start=&quot;2839&quot;&gt;반면 포인트, 주문, 결제, 회원가입 등은 &lt;b&gt;성능과 재시도 용이성&lt;/b&gt;이 중요하여,&lt;br /&gt;낙관적 락으로 처리량을 최적화하였습니다.&lt;/li&gt;
&lt;li data-end=&quot;2958&quot; data-start=&quot;2920&quot;&gt;Redis 분산락으로 다중 서버 환경에서도 확장성을 확보했고,&lt;/li&gt;
&lt;li data-end=&quot;2998&quot; data-start=&quot;2959&quot;&gt;DB 물리적 락은 보조적으로 사용해 병목 현상을 최소화했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;3005&quot; data-start=&quot;3002&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3022&quot; data-start=&quot;3007&quot; data-ke-size=&quot;size26&quot;&gt;8. 한계와 향후 계획&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3177&quot; data-start=&quot;3024&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3073&quot; data-start=&quot;3024&quot;&gt;고경합 구간에 한해 물리적 락 강화 (NOWAIT/WAIT, 타임아웃 정책 적용)&lt;/li&gt;
&lt;li data-end=&quot;3104&quot; data-start=&quot;3074&quot;&gt;분산 락 키 및 TTL 정책을 더 정교하게 설계&lt;/li&gt;
&lt;li data-end=&quot;3119&quot; data-start=&quot;3105&quot;&gt;부하 테스트 자동화&lt;/li&gt;
&lt;li data-end=&quot;3150&quot; data-start=&quot;3120&quot;&gt;EXPLAIN 쿼리 및 인덱스 튜닝 주기적 실시&lt;/li&gt;
&lt;li data-end=&quot;3174&quot; data-start=&quot;3151&quot;&gt;배치 작업 및 메시지 큐 도입 검토&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;3181&quot; data-start=&quot;3178&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3196&quot; data-start=&quot;3183&quot; data-ke-size=&quot;size26&quot;&gt;마무리 한 줄 요약&lt;/h2&gt;
&lt;blockquote data-end=&quot;3260&quot; data-start=&quot;3198&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3260&quot; data-start=&quot;3200&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;도메인 특성별 맞춤 락 전략과 애플리케이션/분산/DB 3계층 보호로 동시성과 성능을 모두 잡았다.&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;3265&quot; data-start=&quot;3262&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;3321&quot; data-start=&quot;3267&quot; data-ke-size=&quot;size16&quot;&gt;궁금한 점이나 추가로 알고 싶은 부분이 있으면 댓글로 남겨주세요!&lt;br /&gt;읽어주셔서 감사합니다.  &lt;/p&gt;
&lt;p data-end=&quot;3321&quot; data-start=&quot;3267&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3321&quot; data-start=&quot;3267&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;248&quot; data-end=&quot;259&quot;&gt;  과제 링크&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;260&quot; data-end=&quot;295&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-start=&quot;260&quot; data-end=&quot;278&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/9&quot;&gt;Step09 PR&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-start=&quot;279&quot; data-end=&quot;295&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/10&quot;&gt;Step10 PR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1754723291617&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;Step09 by seuthootDev &amp;middot; Pull Request #9 &amp;middot; seuthootDev/hanghae-plus-backend&quot; data-og-description=&quot;  PR 제목 규칙 [STEP09] 정승훈 - e-commerce 동시성 처리가 필요하다고 느낀 서비스 비관적 락 (Pessimistic Lock) 쿠폰 발급 선착순 쿠폰의 정확한 순서 보장이 필수 쿠폰 수량이 제한적이고 선착순 원&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/9&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/9&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gnWeL/hyZvtOQPWd/eNrBgB0rRztFeqp6iFLwwk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bhiJWB/hyZvlwuvAv/0e2eet4230Bu3VVOKPJSZK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gnWeL/hyZvtOQPWd/eNrBgB0rRztFeqp6iFLwwk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bhiJWB/hyZvlwuvAv/0e2eet4230Bu3VVOKPJSZK/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;Step09 by seuthootDev &amp;middot; Pull Request #9 &amp;middot; seuthootDev/hanghae-plus-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  PR 제목 규칙 [STEP09] 정승훈 - e-commerce 동시성 처리가 필요하다고 느낀 서비스 비관적 락 (Pessimistic Lock) 쿠폰 발급 선착순 쿠폰의 정확한 순서 보장이 필수 쿠폰 수량이 제한적이고 선착순 원&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;figure id=&quot;og_1754723290803&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;Step10 by seuthootDev &amp;middot; Pull Request #10 &amp;middot; seuthootDev/hanghae-plus-backend&quot; data-og-description=&quot;  PR 제목 규칙 [STEP10] 정승훈 - e-commerce 동시성 처리가 필요하다고 느낀 서비스 비관적 락 (Pessimistic Lock) 쿠폰 발급 선착순 쿠폰의 정확한 순서 보장이 필수 쿠폰 수량이 제한적이고 선착순 원&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/10&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/10&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/IpuY5/hyZvkEkKLq/2GdmYmD7B5R16zm5UZOkA0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/kvOLv/hyZuJ5EY6z/mUEtnHzrNLephgUyzZPsRK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/10&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/IpuY5/hyZvkEkKLq/2GdmYmD7B5R16zm5UZOkA0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/kvOLv/hyZuJ5EY6z/mUEtnHzrNLephgUyzZPsRK/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;Step10 by seuthootDev &amp;middot; Pull Request #10 &amp;middot; seuthootDev/hanghae-plus-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  PR 제목 규칙 [STEP10] 정승훈 - e-commerce 동시성 처리가 필요하다고 느낀 서비스 비관적 락 (Pessimistic Lock) 쿠폰 발급 선착순 쿠폰의 정확한 순서 보장이 필수 쿠폰 수량이 제한적이고 선착순 원&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;</description>
      <category>항해+</category>
      <category>DB</category>
      <category>낙관적락</category>
      <category>동시성</category>
      <category>부트캠프</category>
      <category>부트캠프할인</category>
      <category>비관적락</category>
      <category>추천인코드</category>
      <category>할인</category>
      <category>항해추천인</category>
      <category>항해할인</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/7</guid>
      <comments>https://seuthootdev.tistory.com/7#entry7comment</comments>
      <pubDate>Sat, 9 Aug 2025 19:12:01 +0900</pubDate>
    </item>
    <item>
      <title>항해+ 백엔드 코드 4주차 회고</title>
      <link>https://seuthootdev.tistory.com/6</link>
      <description>&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dA9L8F/btsPDD2R2Ai/N7cRLhuC8AAQz2TF1FUA40/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dA9L8F/btsPDD2R2Ai/N7cRLhuC8AAQz2TF1FUA40/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dA9L8F/btsPDD2R2Ai/N7cRLhuC8AAQz2TF1FUA40/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdA9L8F%2FbtsPDD2R2Ai%2FN7cRLhuC8AAQz2TF1FUA40%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;1600&quot; height=&quot;800&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;이번주의 주된 과제는 '데이터베이스'였다. 이미 구현한 데이터베이스도 있지만, 인덱스 튜닝 등 더 보완해 나가는 주 였다.&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;&lt;i&gt;&lt;u&gt;&lt;b&gt;항해 추천인코드:&amp;nbsp;NYFKU8&lt;/b&gt;&lt;/u&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;78&quot; data-end=&quot;97&quot;&gt;✍️ 이번 주 주제: &lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;데이터베이스&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;99&quot; data-end=&quot;241&quot;&gt;이번 주의 메인 과제는 **'데이터베이스'**였습니다.&lt;br /&gt;이미 지난주에 데이터베이스까지 구현하였지만, 인덱싱 등 더 보완하는 시간을 가졌습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-start=&quot;243&quot; data-end=&quot;246&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;248&quot; data-end=&quot;259&quot;&gt;  과제 링크&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;260&quot; data-end=&quot;295&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-start=&quot;260&quot; data-end=&quot;278&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/6&quot;&gt;Step07 PR&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-start=&quot;279&quot; data-end=&quot;295&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/7&quot;&gt;Step08 PR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-start=&quot;297&quot; data-end=&quot;300&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;302&quot; data-end=&quot;314&quot;&gt; ️ 과제 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;489&quot; data-end=&quot;580&quot;&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;489&quot; data-end=&quot;580&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot; data-start=&quot;536&quot; data-end=&quot;580&quot;&gt;&lt;b&gt;STEP07 - Integration&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(선택) 기존 설계된 테이블 구조의 개선이 필요한 점을 식별하고 ERD에 반영&lt;/li&gt;
&lt;li&gt;Infrastructure Layer 작성&lt;/li&gt;
&lt;li&gt;기능별 통합 테스트 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;STEP08 - DB&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Infrastructure 는 RDBMS ( MySQL ) 기반으로 작성합니다.
&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;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-start=&quot;582&quot; data-end=&quot;585&quot; /&gt;
&lt;h3 data-end=&quot;615&quot; data-start=&quot;596&quot; data-ke-size=&quot;size23&quot;&gt;  데이터베이스 설계 원칙&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;780&quot; data-start=&quot;617&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;657&quot; data-start=&quot;617&quot;&gt;동일 위상의 데이터만 한 테이블에 구성 (ex. 상품과 리뷰는 분리)&lt;/li&gt;
&lt;li data-end=&quot;704&quot; data-start=&quot;658&quot;&gt;컬럼 제약조건 엄격히 설정 (NOT NULL, UNIQUE, DEFAULT 등)&lt;/li&gt;
&lt;li data-end=&quot;737&quot; data-start=&quot;705&quot;&gt;초기 설계부터 인덱싱 고려 (자주 사용되는 컬럼 기준)&lt;/li&gt;
&lt;li data-end=&quot;780&quot; data-start=&quot;738&quot;&gt;정규화로 &lt;b&gt;일관성과 중복 최소화&lt;/b&gt;, 반정규화로 &lt;b&gt;조회 성능 향상&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;785&quot; data-start=&quot;782&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;809&quot; data-start=&quot;787&quot; data-ke-size=&quot;size23&quot;&gt;  인덱스 &amp;amp; 쿼리 최적화 핵심&lt;/h3&gt;
&lt;h4 data-end=&quot;828&quot; data-start=&quot;811&quot; data-ke-size=&quot;size20&quot;&gt;  인덱스 설계 기준&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;955&quot; data-start=&quot;829&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;852&quot; data-start=&quot;829&quot;&gt;&lt;b&gt;조회에 자주 사용되는 컬럼&lt;/b&gt; 우선&lt;/li&gt;
&lt;li data-end=&quot;879&quot; data-start=&quot;853&quot;&gt;&lt;b&gt;중복이 적고&lt;/b&gt; 변경이 적은 컬럼에 설정&lt;/li&gt;
&lt;li data-end=&quot;914&quot; data-start=&quot;880&quot;&gt;&lt;b&gt;복합 인덱스&lt;/b&gt; 설계 시, 선행 컬럼의 카디널리티 고려&lt;/li&gt;
&lt;li data-end=&quot;955&quot; data-start=&quot;915&quot;&gt;&lt;b&gt;LIKE&lt;/b&gt;, &lt;b&gt;IN&lt;/b&gt;, &lt;b&gt;범위 조건&lt;/b&gt;의 인덱스 활용 주의&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;986&quot; data-start=&quot;957&quot; data-ke-size=&quot;size20&quot;&gt;  쿼리 실행 계획 (Query Plan)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1081&quot; data-start=&quot;987&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1028&quot; data-start=&quot;987&quot;&gt;EXPLAIN을 통해 인덱스 활용 여부, 풀 테이블 스캔 여부 확인&lt;/li&gt;
&lt;li data-end=&quot;1081&quot; data-start=&quot;1029&quot;&gt;Using filesort, Using temporary 발생 시 성능 저하 가능성&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;1105&quot; data-start=&quot;1083&quot; data-ke-size=&quot;size20&quot;&gt;  Covering Index&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1159&quot; data-start=&quot;1106&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1159&quot; data-start=&quot;1106&quot;&gt;조회에 필요한 모든 컬럼이 인덱스에 포함되어 있으면 &lt;b&gt;Index Only Scan&lt;/b&gt; 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;1178&quot; data-start=&quot;1161&quot; data-ke-size=&quot;size20&quot;&gt;  동적 확장성 고려&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1268&quot; data-start=&quot;1179&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1220&quot; data-start=&quot;1179&quot;&gt;상품 옵션이 다양해질 경우 &lt;b&gt;옵션 테이블 분리&lt;/b&gt; 구조로 확장성 확보&lt;/li&gt;
&lt;li data-end=&quot;1268&quot; data-start=&quot;1221&quot;&gt;범용적인 옵션 설계 필요 시 &lt;b&gt;키-값 형태&lt;/b&gt; 또는 &lt;b&gt;옵션 유형 분리&lt;/b&gt; 고려&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1273&quot; data-start=&quot;1270&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1298&quot; data-start=&quot;1275&quot; data-ke-size=&quot;size23&quot;&gt;  Sync Schedule 전략&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1369&quot; data-start=&quot;1299&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1336&quot; data-start=&quot;1299&quot;&gt;실시간 정합성보다 주기적인 배치 처리로 &lt;b&gt;조회 성능 극대화&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1369&quot; data-start=&quot;1337&quot;&gt;통계 데이터는 별도 테이블에 저장하여 조회 쿼리 단순화&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1374&quot; data-start=&quot;1371&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;62&quot; data-start=&quot;40&quot; data-ke-size=&quot;size26&quot;&gt;  데이터베이스 설계에 대한 소회&lt;/h2&gt;
&lt;p data-end=&quot;97&quot; data-start=&quot;64&quot; data-ke-size=&quot;size16&quot;&gt;이번 주 멘토링에서 코치님의 인사이트가 특히 기억에 남는다.&lt;/p&gt;
&lt;blockquote data-end=&quot;238&quot; data-start=&quot;99&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;161&quot; data-start=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;비정규화와 정규화는 각각 어떤 상황에 필요할까?&quot;&lt;/b&gt;&lt;br /&gt;이에 대해 코치님은 이렇게 말씀하셨다.&lt;/p&gt;
&lt;p data-end=&quot;238&quot; data-start=&quot;168&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;정규화는 더 이상 정규화할 수 없을 때까지 진행하고,&lt;br /&gt;성능 문제가 발생했을 때 그제서야 비정규화를 고려한다.&quot;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;327&quot; data-start=&quot;240&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;327&quot; data-start=&quot;240&quot; data-ke-size=&quot;size16&quot;&gt;이 말이 인상 깊었던 이유는,&lt;/p&gt;
&lt;p data-end=&quot;414&quot; data-start=&quot;329&quot; data-ke-size=&quot;size16&quot;&gt;코치님은 항상 정해진 답이 없는 문제에도 불구하고,&lt;br /&gt;&lt;b&gt;생각하는 방법과 판단 기준&lt;/b&gt;을 세워주는 분이라는 느낌을 받았기 때문이다.&lt;/p&gt;</description>
      <category>항해+</category>
      <category>DB</category>
      <category>데이터베이스</category>
      <category>동시성</category>
      <category>백엔드</category>
      <category>인덱스</category>
      <category>코딩</category>
      <category>쿼리</category>
      <category>트랜젝션</category>
      <category>항해 추천인코드</category>
      <category>항해플러스</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/6</guid>
      <comments>https://seuthootdev.tistory.com/6#entry6comment</comments>
      <pubDate>Sat, 2 Aug 2025 15:57:59 +0900</pubDate>
    </item>
    <item>
      <title>항해+ 백엔드 코드 3주차 회고</title>
      <link>https://seuthootdev.tistory.com/5</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/llhfM/btsPAmGsgf2/TOLT0UIOKZDsK75Z3u5Kw0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/llhfM/btsPAmGsgf2/TOLT0UIOKZDsK75Z3u5Kw0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/llhfM/btsPAmGsgf2/TOLT0UIOKZDsK75Z3u5Kw0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FllhfM%2FbtsPAmGsgf2%2FTOLT0UIOKZDsK75Z3u5Kw0%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;1600&quot; height=&quot;800&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;이번주의 주된 과제는 '아키텍처'였다. 총 4개의 아키텍처 중 원하는 아키텍처를 선택하고,&lt;/i&gt;&lt;/u&gt;&lt;br /&gt;&lt;u&gt;&lt;i&gt;지난주에 선택한 시나리오(이커머스 웹)를 선택한 아키텍처로 구현해보는 과제였다.&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;&lt;i&gt;&lt;u&gt;&lt;b&gt;항해 추천인코드:&amp;nbsp;NYFKU8&lt;/b&gt;&lt;/u&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;97&quot; data-start=&quot;78&quot; data-ke-size=&quot;size26&quot;&gt;✍️ 이번 주 주제: 아키텍처&lt;/h2&gt;
&lt;p data-end=&quot;241&quot; data-start=&quot;99&quot; data-ke-size=&quot;size16&quot;&gt;이번 주의 메인 과제는 **'아키텍처'**였습니다.&lt;br /&gt;총 4개의 아키텍처(레이어드, 릴레이션 레이어드, 클린, 헥사고날) 중 하나를 선택하고,&lt;br /&gt;지난주에 설정한 &lt;b&gt;이커머스 웹 시나리오&lt;/b&gt;를 기반으로 해당 아키텍처를 적용해 구현하는 것이 목표였습니다.&lt;/p&gt;
&lt;hr data-end=&quot;246&quot; data-start=&quot;243&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;259&quot; data-start=&quot;248&quot; data-ke-size=&quot;size26&quot;&gt;  과제 링크&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;295&quot; data-start=&quot;260&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;278&quot; data-start=&quot;260&quot;&gt;&lt;a href=&quot;#&quot; data-end=&quot;276&quot; data-start=&quot;262&quot;&gt;Step05 PR&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;295&quot; data-start=&quot;279&quot;&gt;&lt;a href=&quot;#&quot; data-end=&quot;295&quot; data-start=&quot;281&quot;&gt;Step06 PR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;300&quot; data-start=&quot;297&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;314&quot; data-start=&quot;302&quot; data-ke-size=&quot;size26&quot;&gt; ️ 과제 요약&lt;/h2&gt;
&lt;h3 data-end=&quot;330&quot; data-start=&quot;316&quot; data-ke-size=&quot;size23&quot;&gt;  STEP 05&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;472&quot; data-start=&quot;331&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;359&quot; data-start=&quot;331&quot;&gt;선택한 아키텍처에 맞춰 &lt;b&gt;패키지 구조 설계&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;379&quot; data-start=&quot;360&quot;&gt;&lt;b&gt;핵심 비즈니스 로직 구현&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;402&quot; data-start=&quot;380&quot;&gt;시나리오 기반 &lt;b&gt;필수 기능 구현&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;472&quot; data-start=&quot;403&quot;&gt;&lt;b&gt;단위 테스트 작성(Mocking/Stub 활용)&lt;/b&gt;&lt;br /&gt;&amp;rarr; 단위 테스트는 외부 의존성 없이 해당 기능 자체에 집중&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;488&quot; data-start=&quot;474&quot; data-ke-size=&quot;size23&quot;&gt;  STEP 06&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;580&quot; data-start=&quot;489&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;511&quot; data-start=&quot;489&quot;&gt;시나리오 기반 &lt;b&gt;추가 기능 구현&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;535&quot; data-start=&quot;512&quot;&gt;각 레이어의 책임을 README에 명시&lt;/li&gt;
&lt;li data-end=&quot;580&quot; data-start=&quot;536&quot;&gt;아키텍처 설계 원칙에 맞춰 &lt;b&gt;책임 분리 및 유지보수성 고려한 구조 개선&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;585&quot; data-start=&quot;582&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;929&quot; data-start=&quot;912&quot; data-ke-size=&quot;size26&quot;&gt;  아키텍처별 핵심 요약&lt;/h2&gt;
&lt;h3 data-end=&quot;974&quot; data-start=&quot;931&quot; data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;레이어드 아키텍처 (Layered Architecture)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled.webp&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4TDMJ/btsPzSlxjrb/MwBAOoIO4RqHoFgqKjv0yk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4TDMJ/btsPzSlxjrb/MwBAOoIO4RqHoFgqKjv0yk/img.webp&quot; data-alt=&quot;Layered Architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4TDMJ/btsPzSlxjrb/MwBAOoIO4RqHoFgqKjv0yk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4TDMJ%2FbtsPzSlxjrb%2FMwBAOoIO4RqHoFgqKjv0yk%2Fimg.webp&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;720&quot; data-filename=&quot;Untitled.webp&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Layered Architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1094&quot; data-start=&quot;975&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;991&quot; data-start=&quot;975&quot;&gt;&lt;b&gt;가장 전통적인 구조&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1034&quot; data-start=&quot;992&quot;&gt;Controller &amp;rarr; Service &amp;rarr; Repository &amp;rarr; DB&lt;/li&gt;
&lt;li data-end=&quot;1053&quot; data-start=&quot;1035&quot;&gt;단순한 CRUD 시스템에 적합&lt;/li&gt;
&lt;li data-end=&quot;1094&quot; data-start=&quot;1054&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: 계층 건너뛰기 유혹, 테스트 어려움, 도메인 로직 분산&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1147&quot; data-start=&quot;1096&quot; data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;릴레이션 레이어드 (Layered + Interface / DIP 적용)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r0M9O/btsPAUbAlAk/86h8kGoOlcUT4jTHVSIHPk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r0M9O/btsPAUbAlAk/86h8kGoOlcUT4jTHVSIHPk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r0M9O/btsPAUbAlAk/86h8kGoOlcUT4jTHVSIHPk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr0M9O%2FbtsPAUbAlAk%2F86h8kGoOlcUT4jTHVSIHPk%2Fimg.webp&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;1024&quot; height=&quot;676&quot; data-filename=&quot;image.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;676&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1300&quot; data-start=&quot;1148&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1176&quot; data-start=&quot;1148&quot;&gt;레이어드는 유지하되, &lt;b&gt;인터페이스로 추상화&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1207&quot; data-start=&quot;1177&quot;&gt;Repository &amp;rarr; Interface &amp;rarr; 구현체&lt;/li&gt;
&lt;li data-end=&quot;1241&quot; data-start=&quot;1208&quot;&gt;DIP 일부 적용 (Service는 인터페이스에만 의존)&lt;/li&gt;
&lt;li data-end=&quot;1276&quot; data-start=&quot;1242&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 유연한 구조, DB 교체 용이, 테스트 가능&lt;/li&gt;
&lt;li data-end=&quot;1300&quot; data-start=&quot;1277&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: 도메인 모델 여전히 빈약&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1347&quot; data-start=&quot;1302&quot; data-ke-size=&quot;size23&quot;&gt;3. &lt;b&gt;헥사고날 아키텍처 (Hexagonal Architecture)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;헥사고날.webp&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/diVHcu/btsPAUJnBuh/5W3CMKl4K8a5FwZKSRUIr0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/diVHcu/btsPAUJnBuh/5W3CMKl4K8a5FwZKSRUIr0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/diVHcu/btsPAUJnBuh/5W3CMKl4K8a5FwZKSRUIr0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdiVHcu%2FbtsPAUJnBuh%2F5W3CMKl4K8a5FwZKSRUIr0%2Fimg.webp&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;980&quot; height=&quot;613&quot; data-filename=&quot;헥사고날.webp&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;613&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1539&quot; data-start=&quot;1348&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1383&quot; data-start=&quot;1348&quot;&gt;도메인 로직을 중심으로, &lt;b&gt;외부 시스템은 어댑터로 처리&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1416&quot; data-start=&quot;1384&quot;&gt;REST, gRPC, MQ 등 다양한 입출력 대응 가능&lt;/li&gt;
&lt;li data-end=&quot;1448&quot; data-start=&quot;1417&quot;&gt;&lt;b&gt;포트(Port)&lt;/b&gt;: 도메인이 요구하는 인터페이스&lt;/li&gt;
&lt;li data-end=&quot;1485&quot; data-start=&quot;1449&quot;&gt;&lt;b&gt;어댑터(Adapter)&lt;/b&gt;: 외부 시스템을 연결하는 구현체&lt;/li&gt;
&lt;li data-end=&quot;1511&quot; data-start=&quot;1486&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 도메인 독립성, 테스트 용이&lt;/li&gt;
&lt;li data-end=&quot;1539&quot; data-start=&quot;1512&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: 작은 프로젝트에 과도할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1580&quot; data-start=&quot;1541&quot; data-ke-size=&quot;size23&quot;&gt;4. &lt;b&gt;클린 아키텍처 (Clean Architecture)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;clean.webp&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;567&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OfOMX/btsPAVn0iXh/lFWcTYdKYGcMSN4HIUK4u0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OfOMX/btsPAVn0iXh/lFWcTYdKYGcMSN4HIUK4u0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OfOMX/btsPAVn0iXh/lFWcTYdKYGcMSN4HIUK4u0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOfOMX%2FbtsPAVn0iXh%2FlFWcTYdKYGcMSN4HIUK4u0%2Fimg.webp&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;772&quot; height=&quot;567&quot; data-filename=&quot;clean.webp&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;567&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1752&quot; data-start=&quot;1581&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1619&quot; data-start=&quot;1581&quot;&gt;&lt;b&gt;UseCase 중심 설계&lt;/b&gt;, 도메인 모델과 유스케이스가 핵심&lt;/li&gt;
&lt;li data-end=&quot;1639&quot; data-start=&quot;1620&quot;&gt;모든 외부 의존성은 내부를 향함&lt;/li&gt;
&lt;li data-end=&quot;1677&quot; data-start=&quot;1640&quot;&gt;도메인 &amp;rarr; UseCase &amp;rarr; Interface &amp;rarr; Adapter&lt;/li&gt;
&lt;li data-end=&quot;1701&quot; data-start=&quot;1678&quot;&gt;&lt;b&gt;DIP 완전 적용&lt;/b&gt;, OCP 준수&lt;/li&gt;
&lt;li data-end=&quot;1725&quot; data-start=&quot;1702&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 유지보수성, 확장성 최고&lt;/li&gt;
&lt;li data-end=&quot;1752&quot; data-start=&quot;1726&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: 인터페이스 과다, 복잡도 높음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-start=&quot;757&quot; data-end=&quot;760&quot; /&gt;
&lt;h2 data-end=&quot;617&quot; data-start=&quot;587&quot; data-ke-size=&quot;size26&quot;&gt;  내가 선택한 아키텍처: &lt;b&gt;클린 아키텍처&lt;/b&gt;&lt;/h2&gt;
&lt;p data-end=&quot;645&quot; data-start=&quot;619&quot; data-ke-size=&quot;size16&quot;&gt;클린 아키텍처를 선택한 이유는 다음과 같습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;755&quot; data-start=&quot;647&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;684&quot; data-start=&quot;647&quot;&gt;&lt;b&gt;비즈니스 로직의 독립성과 테스트 용이성&lt;/b&gt;을 확보할 수 있음&lt;/li&gt;
&lt;li data-end=&quot;718&quot; data-start=&quot;685&quot;&gt;확장성과 유지보수성이 뛰어나고, 명확한 책임 분리가 가능&lt;/li&gt;
&lt;li data-end=&quot;755&quot; data-start=&quot;719&quot;&gt;다양한 UI나 인프라 변경에도 도메인 로직이 영향을 받지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;760&quot; data-start=&quot;757&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;782&quot; data-start=&quot;762&quot; data-ke-size=&quot;size26&quot;&gt;  어려웠던 점 &amp;amp; 해결 방법&lt;/h2&gt;
&lt;h3 data-end=&quot;799&quot; data-start=&quot;784&quot; data-ke-size=&quot;size23&quot;&gt;❗ 가장 어려웠던 점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;896&quot; data-start=&quot;800&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;896&quot; data-start=&quot;800&quot;&gt;처음에는 &lt;b&gt;클린 아키텍처의 구조 자체가 모호&lt;/b&gt;하게 느껴졌습니다.&lt;br /&gt;각 레이어가 어디까지 책임져야 하는지, 어떤 방향으로 의존성이 향해야 하는지 혼란스러웠습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;909&quot; data-start=&quot;898&quot; data-ke-size=&quot;size23&quot;&gt;✅ 해결 전략&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1043&quot; data-start=&quot;910&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;985&quot; data-start=&quot;910&quot;&gt;핵심 원칙인 &lt;b&gt;의존성 역전(Dependency Inversion Principle)&lt;/b&gt; 을 중심으로 구조를 이해하고 구현했습니다.&lt;/li&gt;
&lt;li data-end=&quot;1043&quot; data-start=&quot;986&quot;&gt;아키텍처 전반에 걸쳐 의존성의 방향을 &lt;b&gt;도메인 &amp;rarr; 인터페이스 &amp;rarr; 외부&lt;/b&gt;로 유지하려 노력했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1048&quot; data-start=&quot;1045&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1070&quot; data-start=&quot;1050&quot; data-ke-size=&quot;size26&quot;&gt;  아쉬운 점 &amp;amp; 보완할 부분&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1386&quot; data-start=&quot;1072&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1170&quot; data-start=&quot;1072&quot;&gt;분명 의존성 역전은 구현했지만, 결과적으로 &lt;b&gt;1:1로 매핑된 인터페이스와 구현체&lt;/b&gt;가 많아졌습니다.&lt;br /&gt;&amp;rarr; 실제로 인터페이스의 추상화 역할이 퇴색된 느낌도 들었습니다.&lt;/li&gt;
&lt;li data-end=&quot;1287&quot; data-start=&quot;1172&quot;&gt;&lt;b&gt;파사드 패턴(Facade)&lt;/b&gt;에 대한 이해 부족으로, 중간 조율 역할을 해주는 파사드를 적용하지 못했습니다.&lt;br /&gt;&amp;rarr; 몇몇 레이어는 파사드를 활용해 더 깔끔하게 연결할 수 있었을 것으로 생각합니다.&lt;/li&gt;
&lt;li data-end=&quot;1386&quot; data-start=&quot;1289&quot;&gt;전체 구조가 다소 &lt;b&gt;복잡해졌고, 오히려 개발 생산성이 떨어진 부분도 있음&lt;/b&gt;.&lt;br /&gt;&amp;rarr; 이후에는 &lt;b&gt;복잡성과 실용성 사이의 균형&lt;/b&gt;에 대해 고민해봐야 할 것 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1391&quot; data-start=&quot;1388&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1411&quot; data-start=&quot;1393&quot; data-ke-size=&quot;size26&quot;&gt; &amp;zwj;  팀 코드리뷰 소회&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1590&quot; data-start=&quot;1413&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1475&quot; data-start=&quot;1413&quot;&gt;팀원들의 구조와 설계를 보며 &lt;b&gt;같은 클린 아키텍처를 선택해도 구현 방식이 다양&lt;/b&gt;하다는 점을 체감했습니다.&lt;/li&gt;
&lt;li data-end=&quot;1544&quot; data-start=&quot;1476&quot;&gt;특히, &lt;b&gt;도메인 설계와 추상화 정도에서 차이&lt;/b&gt;가 났는데, 이를 통해 제 코드가 과하게 복잡했는지 돌아보게 됐습니다.&lt;/li&gt;
&lt;li data-end=&quot;1590&quot; data-start=&quot;1545&quot;&gt;다른 사람의 설계를 보며 실용적이고 간결한 방식의 장점도 배울 수 있었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;76&quot; data-start=&quot;58&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;✅ 한 줄 회고&lt;/h2&gt;
&lt;blockquote data-end=&quot;1918&quot; data-start=&quot;1864&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1918&quot; data-start=&quot;1866&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;클린 아키텍처의 핵심은 구조가 아니라 방향성과 책임 분리에 있다는 것을 깨달은 한 주였다.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;div id=&quot;reaction-4&quot; data-tistory-react-app=&quot;Reaction&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>항해+</category>
      <category>DB</category>
      <category>동시성</category>
      <category>부트캠프</category>
      <category>웹</category>
      <category>코딩</category>
      <category>타입스크립트</category>
      <category>프로그래밍</category>
      <category>항해</category>
      <category>항해 추천인코드</category>
      <category>항해+</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/5</guid>
      <comments>https://seuthootdev.tistory.com/5#entry5comment</comments>
      <pubDate>Sat, 26 Jul 2025 19:37:56 +0900</pubDate>
    </item>
    <item>
      <title>항해+ 백엔드 코드 2주차 회고</title>
      <link>https://seuthootdev.tistory.com/4</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deQebp/btsPoUYhxgt/yPlgKmnnDeAP7dswvI5x7K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deQebp/btsPoUYhxgt/yPlgKmnnDeAP7dswvI5x7K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deQebp/btsPoUYhxgt/yPlgKmnnDeAP7dswvI5x7K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeQebp%2FbtsPoUYhxgt%2FyPlgKmnnDeAP7dswvI5x7K%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;1600&quot; height=&quot;800&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;이번주의 주된 과제는 '문서화'였다. 총 8개의 문서를 작성해보았는데,&lt;/i&gt;&lt;/u&gt;&lt;br /&gt;&lt;u&gt;&lt;i&gt;구현 과정에서 문서랑 코드랑 왔다갔다 하면서 자주 업데이트를 하게 되었다.&lt;/i&gt;&lt;/u&gt;&lt;br /&gt;&lt;u&gt;&lt;i&gt;완벽한 문서는 있을 수 없겠지만, 그래도 너무 익숙하지 않아서 힘들었다....&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;i&gt;&lt;u&gt;&lt;b&gt;항해 추천인코드: NYFKU8&lt;/b&gt;&lt;/u&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;119&quot; data-end=&quot;141&quot; data-ke-size=&quot;size26&quot;&gt;✍️ 이번 주 주제:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문서화&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;143&quot; data-end=&quot;221&quot; data-ke-size=&quot;size16&quot;&gt;이번 주의 메인 과제는 '문서화&amp;rsquo;였습니다.&lt;br /&gt;총 8개의 문서를 작성하며, 비즈니스 로직을 분석하고 명확히 표현하는 데 집중했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;143&quot; data-end=&quot;221&quot; data-ke-size=&quot;size16&quot;&gt;또 모든 문서가 일관적이도록 하기 위해서 노력했습니다.&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: start;&quot; data-start=&quot;223&quot; data-end=&quot;389&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-start=&quot;225&quot; data-end=&quot;389&quot; data-ke-size=&quot;size16&quot;&gt;과제 링크&lt;br /&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/2&quot; data-start=&quot;235&quot; data-end=&quot;309&quot;&gt;  Step03 PR&lt;/a&gt;&lt;br /&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/seuthootDev/hanghae-plus-backend/pull/23&quot; data-start=&quot;314&quot; data-end=&quot;389&quot;&gt;  Step04 PR&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-start=&quot;391&quot; data-end=&quot;394&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;396&quot; data-end=&quot;411&quot; data-ke-size=&quot;size26&quot;&gt; ️ 과제 내용 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;413&quot; data-end=&quot;555&quot;&gt;
&lt;li data-start=&quot;413&quot; data-end=&quot;480&quot;&gt;&lt;b&gt;STEP 03 - 분석&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;434&quot; data-end=&quot;480&quot;&gt;
&lt;li data-start=&quot;434&quot; data-end=&quot;480&quot;&gt;시나리오 요구사항 분석 및 문서 작성 (e.g. 시퀀스 다이어그램, ERD 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-start=&quot;481&quot; data-end=&quot;555&quot;&gt;&lt;b&gt;STEP 04 - 실행&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;502&quot; data-end=&quot;555&quot;&gt;
&lt;li data-start=&quot;502&quot; data-end=&quot;528&quot;&gt;Mock API 및 Swagger 문서 작성&lt;/li&gt;
&lt;li data-start=&quot;531&quot; data-end=&quot;555&quot;&gt;(선택 과제) API E2E 테스트 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-start=&quot;557&quot; data-end=&quot;560&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;562&quot; data-end=&quot;577&quot; data-ke-size=&quot;size26&quot;&gt;  작성한 문서 목록&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;579&quot; data-end=&quot;621&quot; data-ke-size=&quot;size16&quot;&gt;총 8개의 문서를 docs/ 디렉토리 내 .md 파일로 작성했습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;623&quot; data-end=&quot;700&quot;&gt;
&lt;li data-start=&quot;623&quot; data-end=&quot;633&quot;&gt;요구사항 명세서&lt;/li&gt;
&lt;li data-start=&quot;634&quot; data-end=&quot;641&quot;&gt;유스케이스&lt;/li&gt;
&lt;li data-start=&quot;642&quot; data-end=&quot;649&quot;&gt;정책 문서&lt;/li&gt;
&lt;li data-start=&quot;650&quot; data-end=&quot;659&quot;&gt;API 명세서&lt;/li&gt;
&lt;li data-start=&quot;660&quot; data-end=&quot;665&quot;&gt;ERD&lt;/li&gt;
&lt;li data-start=&quot;666&quot; data-end=&quot;677&quot;&gt;클래스 다이어그램&lt;/li&gt;
&lt;li data-start=&quot;678&quot; data-end=&quot;688&quot;&gt;상태 다이어그램&lt;/li&gt;
&lt;li data-start=&quot;689&quot; data-end=&quot;700&quot;&gt;시퀀스 다이어그램&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-start=&quot;702&quot; data-end=&quot;705&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;707&quot; data-end=&quot;724&quot; data-ke-size=&quot;size26&quot;&gt;  Mermaid 도입기&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;726&quot; data-end=&quot;765&quot; data-ke-size=&quot;size16&quot;&gt;처음으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Mermaid&lt;/b&gt;라는 도구를 써봤는데, 정말 강력했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;726&quot; data-end=&quot;765&quot; 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;다운로드.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C80nV/btsPpSei5O4/MG57KI5ooTHaNo7AlaCJUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C80nV/btsPpSei5O4/MG57KI5ooTHaNo7AlaCJUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C80nV/btsPpSei5O4/MG57KI5ooTHaNo7AlaCJUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC80nV%2FbtsPpSei5O4%2FMG57KI5ooTHaNo7AlaCJUK%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;1200&quot; height=&quot;630&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: start;&quot; data-start=&quot;767&quot; data-end=&quot;852&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-start=&quot;769&quot; data-end=&quot;852&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Mermaid란?&lt;/b&gt;&lt;br /&gt;Markdown 기반으로 플로우차트, ERD, 시퀀스 다이어그램 등을 코드로 그릴 수 있게 해주는 문서화 도구&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;854&quot; data-end=&quot;957&quot; data-ke-size=&quot;size16&quot;&gt;회사에서는 이전까지 문서를 주로 Figma로 작성했었는데, 이미지로 저장 후 프로젝트에 넣다 보니&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;수정 시 다시 Figma를 열어야 했고, 최신화도 어렵고 귀찮은 작업&lt;/b&gt;이었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;959&quot; data-end=&quot;1081&quot; data-ke-size=&quot;size16&quot;&gt;하지만 Mermaid는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Markdown 문서에서 바로 수정 및 커밋이 가능&lt;/b&gt;하기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문서 수정이 간편하고, 협업 시에도 효율적&lt;/b&gt;입니다.&lt;br /&gt;이 좋은 걸 이제야 알았다니... 늦게나마 알게 돼서 다행입니다.&lt;/p&gt;
&lt;hr data-start=&quot;1083&quot; data-end=&quot;1086&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;1088&quot; data-end=&quot;1107&quot; data-ke-size=&quot;size26&quot;&gt;  어려웠던 점과 해결 방법&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;1109&quot; data-end=&quot;1124&quot; 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; data-start=&quot;1125&quot; data-end=&quot;1188&quot;&gt;
&lt;li data-start=&quot;1125&quot; data-end=&quot;1188&quot;&gt;&lt;b&gt;비즈니스 로직을 잘 몰라서&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;어떤 정책이 필요한지, 어떤 문서를 작성해야 하는지 감을 잡기 어려웠습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;1190&quot; data-end=&quot;1201&quot; 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; data-start=&quot;1202&quot; data-end=&quot;1321&quot;&gt;
&lt;li data-start=&quot;1202&quot; data-end=&quot;1272&quot;&gt;&lt;b&gt;큰 틀 &amp;rarr; 작은 틀&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;순서로 접근
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;1228&quot; data-end=&quot;1272&quot;&gt;
&lt;li data-start=&quot;1228&quot; data-end=&quot;1272&quot;&gt;예) 요구사항 명세서 &amp;rarr; API 명세서 &amp;rarr; ERD &amp;rarr; 시퀀스/상태 다이어그램&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-start=&quot;1273&quot; data-end=&quot;1321&quot;&gt;점점 비즈니스 로직이 눈에 들어오기 시작했고, 문서 작성 속도도 점차 빨라졌습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-start=&quot;1323&quot; data-end=&quot;1326&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;1328&quot; data-end=&quot;1350&quot; data-ke-size=&quot;size26&quot;&gt;  Swagger와 E2E 테스트&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;1352&quot; data-end=&quot;1455&quot; data-ke-size=&quot;size16&quot;&gt;Swagger나 E2E 테스트 코드는 처음 작성해봐서 익숙하지 않았지만,&lt;br /&gt;문서화 덕분에 로직을 이해한 상태였기에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Mock API로 구현 자체는 무난&lt;/b&gt;하게 진행할 수 있었습니다.&lt;/p&gt;
&lt;hr data-start=&quot;1457&quot; data-end=&quot;1460&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;1462&quot; data-end=&quot;1485&quot; data-ke-size=&quot;size26&quot;&gt;  멘토의 한마디에서 얻은 인사이트&lt;/h2&gt;
&lt;blockquote style=&quot;color: #666666; text-align: start;&quot; data-start=&quot;1487&quot; data-end=&quot;1514&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-start=&quot;1489&quot; data-end=&quot;1514&quot; data-ke-size=&quot;size16&quot;&gt;&quot;문서화가 필요 없게 하는 것이 가장 좋다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;1516&quot; data-end=&quot;1634&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 문서화 과제 주간에 이런 말씀을 들어서 놀랐지만, 곧 이 말에 공감됐습니다.&lt;br /&gt;&lt;b&gt;문서는 결국 또 하나의 유지보수 대상&lt;/b&gt;이기 때문에, 코드만 보고도 이해할 수 있는 구조를 만든다면 가장 이상적이겠죠.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;1636&quot; data-end=&quot;1703&quot; data-ke-size=&quot;size16&quot;&gt;다음 프로젝트에서는 Plasma Markdown, Nestia 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자동 문서화 툴&lt;/b&gt;도 활용해보고 싶습니다.&lt;/p&gt;
&lt;hr data-start=&quot;1705&quot; data-end=&quot;1708&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;62&quot; data-start=&quot;44&quot; data-ke-size=&quot;size26&quot;&gt; &amp;zwj;  팀 코드리뷰 소회&lt;/h2&gt;
&lt;h3 data-end=&quot;85&quot; data-start=&quot;64&quot; data-ke-size=&quot;size23&quot;&gt;1. 동시성 처리 문서화의 부족&lt;/h3&gt;
&lt;p data-end=&quot;174&quot; data-start=&quot;87&quot; data-ke-size=&quot;size16&quot;&gt;팀원들의 문서를 살펴보면서 &lt;b&gt;내가 놓친 부분들&lt;/b&gt;이 눈에 띄었는데,&lt;br /&gt;그 중 가장 아쉬웠던 점은 &lt;b&gt;동시성 처리에 대한 문서화가 부족했다는 점&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;262&quot; data-start=&quot;176&quot; data-ke-size=&quot;size16&quot;&gt;사실 동시성 처리에 대해서 아직 잘 이해하지 못한 상태여서,&lt;br /&gt;문서에서는 단순히 &quot;동시성 처리가 필요하다&quot; 정도로만 &lt;b&gt;추상적으로 언급&lt;/b&gt;했었습니다.&lt;/p&gt;
&lt;h3 data-end=&quot;302&quot; data-start=&quot;269&quot; data-ke-size=&quot;size23&quot;&gt;2. 주문 생성 vs 결제 처리 - 서비스 분리 여부&lt;/h3&gt;
&lt;p data-end=&quot;424&quot; data-start=&quot;304&quot; data-ke-size=&quot;size16&quot;&gt;또 하나 흥미로웠던 점은 &lt;b&gt;서비스 분리 방식&lt;/b&gt;이었습니다.&lt;br /&gt;저는 &lt;b&gt;주문 생성과 결제 처리를 별도의 서비스로 분리&lt;/b&gt;했는데,&lt;br /&gt;대부분 팀원들은 &lt;b&gt;주문 서비스 하나에서 둘 다 처리&lt;/b&gt;하는 방식을 택하셨습니다.&lt;/p&gt;
&lt;p data-end=&quot;454&quot; data-start=&quot;426&quot; data-ke-size=&quot;size16&quot;&gt;제가 서비스 분리를 선택한 이유는 다음과 같습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;541&quot; data-start=&quot;456&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;489&quot; data-start=&quot;456&quot;&gt;사용자가 &lt;b&gt;결제를 나중에 진행&lt;/b&gt;할 수도 있다고 생각함&lt;/li&gt;
&lt;li data-end=&quot;541&quot; data-start=&quot;490&quot;&gt;결제 도중 &lt;b&gt;페이지 이탈&lt;/b&gt;이나 &lt;b&gt;PG사 에러&lt;/b&gt;와 같은 예외 상황 발생 가능성 고려&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;606&quot; data-start=&quot;543&quot; data-ke-size=&quot;size16&quot;&gt;따라서 저는 &lt;b&gt;주문은 먼저 생성&lt;/b&gt;하고, 결제는 &lt;b&gt;별도 절차로 처리&lt;/b&gt;하는 구조가 더 유연하다고 판단했습니다.&lt;/p&gt;
&lt;hr data-start=&quot;1998&quot; data-end=&quot;2001&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;2003&quot; data-end=&quot;2021&quot; data-ke-size=&quot;size26&quot;&gt;  다음 주 목표 &amp;amp; 다짐&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;2023&quot; data-end=&quot;2054&quot; data-ke-size=&quot;size16&quot;&gt;이번 주는 기본 과제와 심화 과제 모두&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;PASS&lt;/b&gt;!&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: start;&quot; data-start=&quot;2056&quot; data-end=&quot;2120&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-start=&quot;2058&quot; data-end=&quot;2120&quot; data-ke-size=&quot;size16&quot;&gt;다음 주에도 좋은 결과를 얻으려면&lt;br /&gt;&lt;b&gt;일요일~화요일까지 시간을 어떻게 쓰느냐가 핵심&lt;/b&gt;이라고 생각합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;2122&quot; data-end=&quot;2204&quot;&gt;
&lt;li data-start=&quot;2122&quot; data-end=&quot;2145&quot;&gt;&lt;b&gt;화요일 전까지 기본 과제 마무리&lt;/b&gt;&lt;/li&gt;
&lt;li data-start=&quot;2146&quot; data-end=&quot;2174&quot;&gt;&lt;b&gt;남은 시간엔 심화 과제에 깊이 있게 집중&lt;/b&gt;&lt;/li&gt;
&lt;li data-start=&quot;2175&quot; data-end=&quot;2204&quot;&gt;&lt;b&gt;멘토링 전에 사전 학습과 질문 준비 철저히&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;2206&quot; data-end=&quot;2268&quot; data-ke-size=&quot;size16&quot;&gt;지난주엔 준비가 부족해서 멘토링 시간 이후 아쉬움이 남았기에,&lt;br /&gt;이번에는 훨씬 더 알차게 준비해보려고 합니다.&lt;/p&gt;
&lt;hr data-start=&quot;2270&quot; data-end=&quot;2273&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;2275&quot; data-end=&quot;2286&quot; data-ke-size=&quot;size26&quot;&gt;✅ 한 줄 회고&lt;/h2&gt;
&lt;blockquote style=&quot;color: #666666; text-align: start;&quot; data-start=&quot;2288&quot; data-end=&quot;2389&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-start=&quot;2290&quot; data-end=&quot;2389&quot; data-ke-size=&quot;size16&quot;&gt;&quot;문서를 작성하며 비즈니스 로직을 자연스럽게 이해했고, Mermaid 덕분에 협업 가능한 문서화 경험을 얻을 수 있었다.&lt;br /&gt;이제는 코드만으로도 문서가 되는 구조를 꿈꾼다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>항해+</category>
      <category>동시성</category>
      <category>부트캠프</category>
      <category>웹</category>
      <category>웹 개발</category>
      <category>코딩</category>
      <category>타입스크립트</category>
      <category>프로그래밍</category>
      <category>항해</category>
      <category>항해 추천인코드</category>
      <category>항해+</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/4</guid>
      <comments>https://seuthootdev.tistory.com/4#entry4comment</comments>
      <pubDate>Sun, 20 Jul 2025 13:07:09 +0900</pubDate>
    </item>
    <item>
      <title>항해+ 백엔드 코드 1주차 회고</title>
      <link>https://seuthootdev.tistory.com/3</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lUewZ/btsPfGZqXu9/AwXu8XOQrkf1sGqJvZZDnK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lUewZ/btsPfGZqXu9/AwXu8XOQrkf1sGqJvZZDnK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lUewZ/btsPfGZqXu9/AwXu8XOQrkf1sGqJvZZDnK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlUewZ%2FbtsPfGZqXu9%2FAwXu8XOQrkf1sGqJvZZDnK%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;1600&quot; height=&quot;800&quot; data-filename=&quot;항해.jpg&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;800&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;정말 바쁜 한 주가 지나갔다. 물론 이제 시작이고 앞으로 9주가 더 남았다......&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 웹 개발자가 아니라서 학습하는 거의 대부분이 생소한 개념들이라 과제도 바로 시작을 못하고, 개념부터 학습하는 방식으로 작업하다 보니, 정말 많은 시간이 필요했고, 이번주엔 회식도 겹치는 바람에 더 시간이 없었다. ㅜㅜ&lt;br /&gt;과제에서 얻을 수 있었던게 100이라면, 난 30만 얻은 것 같다. 하지만 30이라도 확실히 내 것으로 만들었다는 것이 중요한 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-start=&quot;104&quot; data-end=&quot;129&quot;&gt;1. 과제내용&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;STEP01 - 기능 추가 및 테스트 구현&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;4가지 기본 기능 (포인트 조회, 포인트 충전/사용 내역 조회, 충전, 사용)에 대한 구현&lt;/li&gt;
&lt;li&gt;4가지 기본 기능에 대한 테스트 작성&lt;/li&gt;
&lt;li&gt;단, 이때 /database 패키지의 구현체는 수정하지 않고, 이를 활용해 기능을 구현함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;STEP02- 동시성 학습 및 구현&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일한 사용자에 대한 동시 요청에 대한 테스트를 먼저 작성함&lt;/li&gt;
&lt;li&gt;이후 해당 테스트가 정상적으로 처리될 수 있도록 개선함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;선택한 언어에 대한&lt;/b&gt; 동시성 제어 방식 및 각 적용의 장/단점을 기술한 보고서 작성 ( &lt;b&gt;&lt;a href=&quot;http://README.md&quot;&gt;README.md&lt;/a&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;&lt;a href=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/seuthootDev/hanghae99-backend-week1/pull/1&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752323452798&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;Step01 by seuthootDev &amp;middot; Pull Request #1 &amp;middot; seuthootDev/hanghae99-backend-week1&quot; data-og-description=&quot;커밋 링크 서비스 테스트 코드 완료 : a6be6b5 레포지토리 테스트 코드 완료 : 03d7c51 컨트롤러 테스트 코드 완료 : 3a64440 통합 테스트 코드 완료 : 15741d8 리뷰 포인트(질문) 리뷰 포인트: 테스트에서 &quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/1&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dfrqUt/hyZjkR9lT3/xKoI3xERK63eK12Q0k2QS1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bUaN32/hyZjqybbm6/y5HGdo4PtfxHFe0ZK9jIUK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dfrqUt/hyZjkR9lT3/xKoI3xERK63eK12Q0k2QS1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bUaN32/hyZjqybbm6/y5HGdo4PtfxHFe0ZK9jIUK/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;Step01 by seuthootDev &amp;middot; Pull Request #1 &amp;middot; seuthootDev/hanghae99-backend-week1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;커밋 링크 서비스 테스트 코드 완료 : a6be6b5 레포지토리 테스트 코드 완료 : 03d7c51 컨트롤러 테스트 코드 완료 : 3a64440 통합 테스트 코드 완료 : 15741d8 리뷰 포인트(질문) 리뷰 포인트: 테스트에서&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;&lt;a href=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/2&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/seuthootDev/hanghae99-backend-week1/pull/2&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752323473041&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;Step02 by seuthootDev &amp;middot; Pull Request #2 &amp;middot; seuthootDev/hanghae99-backend-week1&quot; data-og-description=&quot;커밋 링크 tset: 동시성 테스트 케이스 추가 : dd5fb01 tset : 서비스 동시성 제어 : 3562bea 리뷰 포인트(질문) 리뷰 포인트: 동시성 제어 구현 현재 포인트 시스템에 사용자별 뮤텍스를 적용하여 동시성&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/2&quot; data-og-url=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dDiO18/hyZjpMNOMG/zQ2kocwvw9bK57UaVD8uE1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/RD31t/hyZjmI9UMu/vAnm6ik4kuKQrZpExXgZAK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seuthootDev/hanghae99-backend-week1/pull/2&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dDiO18/hyZjpMNOMG/zQ2kocwvw9bK57UaVD8uE1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/RD31t/hyZjmI9UMu/vAnm6ik4kuKQrZpExXgZAK/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;Step02 by seuthootDev &amp;middot; Pull Request #2 &amp;middot; seuthootDev/hanghae99-backend-week1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;커밋 링크 tset: 동시성 테스트 케이스 추가 : dd5fb01 tset : 서비스 동시성 제어 : 3562bea 리뷰 포인트(질문) 리뷰 포인트: 동시성 제어 구현 현재 포인트 시스템에 사용자별 뮤텍스를 적용하여 동시성&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과제는 기본, 심화 2가지 step이 있었고, 개별 브랜치로 pr해서 링크를 제출하는 방식으로 제출했다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-start=&quot;484&quot; data-end=&quot;487&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-start=&quot;489&quot; data-end=&quot;510&quot;&gt;2. 과제 진행 과정&lt;/h3&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;511&quot; data-end=&quot;603&quot;&gt;이번 과제는 TTD 기반의 포인트 충전 API 작성 + 동시성 제어였다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;680&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbdE3t/btsPghksRMO/fablzCWYlAlvaJQuB58klk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbdE3t/btsPghksRMO/fablzCWYlAlvaJQuB58klk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbdE3t/btsPghksRMO/fablzCWYlAlvaJQuB58klk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbdE3t%2FbtsPghksRMO%2FfablzCWYlAlvaJQuB58klk%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;1024&quot; height=&quot;680&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;680&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #4a5568; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;TDD란 Test Driven Development의 약자로 &amp;lsquo;테스트 주도 개발&amp;rsquo;이라고 한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #4a5568; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;반복 테스트를 이용한 소프트웨어 방법론으로 작은 단위의 테스트 케이스를 작성하고 이를 통과하는 코드를 추가하는 단계를 반복하여 구현한다. 특징적인 것은 &quot;테스트 코드를 먼저 작성하는 개발 방법론&quot;이라는 것이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #4a5568; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;151&quot; data-start=&quot;33&quot; data-ke-size=&quot;size16&quot;&gt;이번 과제에서는 동시성 제어보다 TDD에 더 많은 시간을 쏟게 되었다. 웹 개발 자체에 익숙하지 않다 보니 기능 구현에 많은 시간이 필요했고, 테스트 코드를 작성하는 데에도 상당한 시간을 투자하게 되었기 때문이다.&lt;/p&gt;
&lt;p data-end=&quot;318&quot; data-start=&quot;153&quot; data-ke-size=&quot;size16&quot;&gt;이번 과제를 통해 테스트 코드의 필요성과 유용성에 대해 깊이 생각해보는 계기가 되었다. 항해 본 과정을 시작하기 전에 동기들과 함께한 사전 스터디에서는 Postman을 사용해 수동으로 테스트를 진행했었는데, &lt;b&gt;테스트 코드를 작성해서 자동화하는 방식이 훨씬 효율적이였다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;671&quot; data-start=&quot;320&quot; data-ke-size=&quot;size16&quot;&gt;사실 지금 다니는 회사에서는 테스트 코드를 따로 작성하지 않고 있었지만, 지난주에는 내가 작성한 모든 파일에 테스트 코드를 작성했다. 테스트 도구를 활용한 것은 아니지만, Python 프로젝트에서 main.py를 실행하는 방식 대신, 의존성 있는 파일을 직접 실행해서 테스트할 수 있도록 구성했다.&lt;b&gt; 이 과정에서 직접 Mock 클래스를 구현해 사용했는데, 과제를 통해 처음 접한 &amp;lsquo;모킹&amp;rsquo;이라는 개념을 바로 실무에 적용했다는 것이 신기했다.&lt;/b&gt; 실무 환경은 웹 개발이 아니지만, 테스트라는 개념은 개발 전반에 걸쳐 통용될 수 있다는 점에서, 나만의 개발 철학이 하나 생긴 것 같았다.&lt;/p&gt;
&lt;p data-end=&quot;811&quot; data-start=&quot;673&quot; data-ke-size=&quot;size16&quot;&gt;심화 과제였던 동시성 제어는 async-mutex 라이브러리를 활용해 구현해보았지만, 시간 부족으로 깊이 있게 학습하지는 못했다. 다행히 3~4주차 과제에서 다시 다룰 기회가 있다고 하니, 그때는 더 시간을 들여 제대로 학습해보고 싶다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-start=&quot;758&quot; data-end=&quot;761&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-start=&quot;763&quot; data-end=&quot;787&quot;&gt;3. 어려웠던 점 &amp;amp; 해결 방법&lt;/h3&gt;
&lt;p style=&quot;color: #222222; text-align: left;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;788&quot; data-end=&quot;908&quot;&gt;TDD 관련해서 어려웠던게 몇가지 있는데,&lt;br /&gt;&amp;nbsp;- TDD 싸이클은 얼마나 지켜야 하지?&lt;br /&gt;&amp;nbsp;- 테스트 커버리지는 목표를 어느정도로 잡아야하지?&lt;br /&gt;&amp;nbsp;- 모킹은 언제 활용하고 또 언제 활용하면 안 되지?&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-end=&quot;252&quot; data-start=&quot;203&quot; data-ke-size=&quot;size16&quot;&gt;이 외에도 고민이 많았지만, 공통점은 모두 '명확한 정답이 없는 문제'라는 점이다.&lt;/p&gt;
&lt;p data-end=&quot;394&quot; data-start=&quot;254&quot; data-ke-size=&quot;size16&quot;&gt;항해에서는 매주 팀별로 코치님과의 온라인 멘토링 시간이 주어지며, 다른 팀의 멘토링을 청강하는 것도 허용된다. 나 또한 우리 팀뿐만 아니라 다른 팀의 멘토링, 전체 Q&amp;amp;A 시간을 적극 활용하면서 여러 인사이트를 얻었고, 결국 나만의 결론에 도달했다.&lt;/p&gt;
&lt;p data-end=&quot;576&quot; data-start=&quot;396&quot; data-ke-size=&quot;size16&quot;&gt;그 결론은 바로 &quot;&lt;b&gt;비즈니스적 가치를 기준으로 판단하자&lt;/b&gt;&quot;였다.&lt;br /&gt;TDD 사이클처럼 &amp;lsquo;방식&amp;rsquo; 자체에 너무 얽매일 필요는 없고, 상황과 조건에 따라 유연하게 접근하는 것이 더 중요하다고 느꼈다. 테스트 커버리지나 모킹 여부도 마찬가지다. 정답이 아닌 &amp;lsquo;적합한 선택&amp;rsquo;을 하는 것이 핵심이다.&lt;/p&gt;
&lt;p data-end=&quot;812&quot; data-start=&quot;578&quot; data-ke-size=&quot;size16&quot;&gt;물론 아직 나는 상황 판단의 눈이 충분히 갖춰져 있진 않다. 그래서 이번에는 &lt;b&gt;기본을 최대한 지키되, 생산성과 효율을 고려한 융통성을 곁들이는 방식&lt;/b&gt;으로 접근했다.&lt;br /&gt;예를 들어, TDD의 원칙은 &amp;lsquo;레드-그린-리팩터&amp;rsquo; 순서지만, 작업 중에는 먼저 그린 단계(기능 구현)를 진행한 뒤 테스트 코드를 작성하는 경우도 있었다. 그 방식이 개발 흐름과 생산성을 더 잘 살려준다고 판단했기 때문이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-start=&quot;1123&quot; data-end=&quot;1126&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-start=&quot;1128&quot; data-end=&quot;1145&quot;&gt;4. TypeScript 팀 화이팅&lt;/h3&gt;
&lt;p data-end=&quot;213&quot; data-start=&quot;66&quot; data-ke-size=&quot;size16&quot;&gt;우리 팀은 정말 실력자들로만 구성된 것 같다. 물론... 나를 제외하고 말이다.&lt;br /&gt;이게 팔이 안으로 굽는게 아니라, 진심으로 그렇게 생각하고 있다. TypeScript 언어는 물론, NestJS 프레임워크 활용 능력이나 개발에 대한 철학까지 모두 다들 뛰어난 분들이다.&lt;/p&gt;
&lt;p data-end=&quot;338&quot; data-start=&quot;215&quot; data-ke-size=&quot;size16&quot;&gt;항해에서는 사용하는 언어 기준으로 팀을 나누는데, TS를 사용하는 팀은 우리 팀이 유일하다. 이유는 정확히 모르겠지만, 우리나라에서는 아직 TypeScript를 사용하는 회사가 별로 없기 때문이라고 생각한다.&lt;/p&gt;
&lt;p data-end=&quot;645&quot; data-start=&quot;340&quot; data-ke-size=&quot;size16&quot;&gt;그런데 솔직히 말하면, 지금 이 상황이 나에게는 오히려 좋은 기회다.&lt;br /&gt;항해에서는 매주 랜덤 코드 리뷰를 진행하는데, 팀을 섞어서 다른 사람들과 코드 리뷰를 하게 된다. 실력자들은 다양한 시각과 네트워킹을 위해 매주 새로운 사람들과 리뷰하는 걸 좋아할 수 있지만, 나는 아직 초심자라서 내 실력을 잘 파악하고, 정확한 피드백을 줄 수 있는 &lt;b&gt;우리 팀원들과 꾸준히 리뷰를 할 수 있는 점이 오히려 더 큰 행운&lt;/b&gt;이라고 느낀다. 오늘도 팀원들로부터 정말 많은 피드백을 받았고, 하나하나가 큰 도움이 되었다. 팀원들에게 진심으로 감사하다.&lt;/p&gt;
&lt;p data-end=&quot;802&quot; data-start=&quot;647&quot; data-ke-size=&quot;size16&quot;&gt;회사에서는 주로 혼자 개발을 하다 보니 협업의 경험이 부족했는데, 이번 과제를 하며 팀원들이 실무에서 협업하는 방식, 코드 리뷰에서 나오는 다양한 시각들을 접하면서 많은 인사이트를 얻고 있다. 단순히 기술적인 성장을 넘어, 협업하는 개발자로서도 한 걸음 나아가고 있는 느낌이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;1498&quot; data-start=&quot;1481&quot; data-ke-size=&quot;size23&quot;&gt;5.&lt;span&gt; 다음 주 목표 &amp;amp; 다짐&lt;/span&gt;&lt;/h3&gt;
&lt;figure style=&quot;color: #333333; text-align: center;&quot; contenteditable=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/007.gif&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-name=&quot;007&quot; data-emoticon-type=&quot;friends1&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;emoticon&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/007.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-end=&quot;77&quot; data-start=&quot;34&quot; data-ke-size=&quot;size16&quot;&gt;이번 주 과제는 다행히 기본 과제와 심화 과제 모두 &lt;b&gt;PASS&lt;/b&gt;를 받았다.&lt;/p&gt;
&lt;p data-end=&quot;262&quot; data-start=&quot;79&quot; data-ke-size=&quot;size16&quot;&gt;다음 주에도 좋은 결과를 얻기 위해서는 &lt;b&gt;일요일부터 화요일까지의 시간을 어떻게 쓰느냐가 정말 중요하다&lt;/b&gt;고 생각한다. 특히, 코치님과의 멘토링 시간을 효과적으로 활용하려면 사전 학습이 필수다.&lt;br /&gt;사실 지난주 멘토링 때는 준비가 부족해서, 멘토링이 끝난 뒤에야 &quot;아, 그때 이걸 물어봤어야 했는데...&quot; 하는 아쉬움이 많았다.&lt;/p&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;264&quot; data-ke-size=&quot;size16&quot;&gt;또한 애초에 과제를 하는 시간이 넉넉하지는 않다. 그래서 이번 주는 &lt;b&gt;화요일 전까지 기본 과제를 마무리하고&lt;/b&gt;, 남은 시간 동안 &lt;b&gt;심화 과제를 더 깊이 있게 학습&lt;/b&gt;하는 것을 목표로 삼았다.&lt;br /&gt;이번에는 더 효율적인 시간 활용과 준비를 통해, 더 의미 있는 한 주를 만들어보고 싶다.&lt;/p&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;264&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;264&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;264&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;264&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;264&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;항해 추천인코드:NYFKU8&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;1526&quot; data-end=&quot;1652&quot;&gt;&lt;b&gt;20만원 할인 받으세요~&lt;/b&gt;&lt;/p&gt;</description>
      <category>항해+</category>
      <category>동시성</category>
      <category>부트캠프</category>
      <category>웹</category>
      <category>웹 개발</category>
      <category>코딩</category>
      <category>타입스크립트</category>
      <category>프로그래밍</category>
      <category>항해</category>
      <category>항해 추천인코드</category>
      <category>항해+</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/3</guid>
      <comments>https://seuthootdev.tistory.com/3#entry3comment</comments>
      <pubDate>Sat, 12 Jul 2025 22:17:45 +0900</pubDate>
    </item>
    <item>
      <title>항해 플러스 백엔드 9기를 시작하는 마음(항해 추천인코드 있음)</title>
      <link>https://seuthootdev.tistory.com/2</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-05 234839.png&quot; data-origin-width=&quot;1465&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RlOjz/btsO5mm8Q2S/k9KK9pkanUOafmcdaj5rRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RlOjz/btsO5mm8Q2S/k9KK9pkanUOafmcdaj5rRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RlOjz/btsO5mm8Q2S/k9KK9pkanUOafmcdaj5rRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRlOjz%2FbtsO5mm8Q2S%2Fk9KK9pkanUOafmcdaj5rRK%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;1465&quot; height=&quot;822&quot; data-filename=&quot;스크린샷 2025-07-05 234839.png&quot; data-origin-width=&quot;1465&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-end=&quot;129&quot; data-start=&quot;104&quot; data-ke-size=&quot;size23&quot;&gt;1. 지금까지의 개발자 커리어 회고&lt;/h3&gt;
&lt;p data-end=&quot;205&quot; data-start=&quot;130&quot; data-ke-size=&quot;size16&quot;&gt;나는 약 2년간 영업관리직으로 근무하다, 현재는 파이썬 기반의 데스크톱 애플리케이션 개발자로 1년 넘게 일하고 있다.&lt;/p&gt;
&lt;p data-end=&quot;338&quot; data-start=&quot;207&quot; data-ke-size=&quot;size16&quot;&gt;영업직을 그만두고 새로운 직장을 찾던 중 문득 이런 생각이 들었다.&lt;br /&gt;&amp;ldquo;전 회사에서 배운 생산라인, 공정, 물류 시스템, 전산, 상품 지식들이 다른 회사에서는 무용지물 아닌가? 내가 정말 영업에서 내세울 만한 게 있을까?&amp;rdquo;&lt;/p&gt;
&lt;p data-end=&quot;482&quot; data-start=&quot;340&quot; data-ke-size=&quot;size16&quot;&gt;이러한 고민 끝에, &lt;b&gt;변화가 많은 환경에서도 통용될 수 있는 &amp;lsquo;기술&amp;rsquo;을 가진 사람이 되고 싶다는 결심&lt;/b&gt;을 하게 되었고, 그렇게 개발자의 길에 들어섰다. 늦은 나이에 시작했지만 운이 좋게도 취업에 성공했고, 개발자로서의 인생을 시작하게 되었다.&lt;/p&gt;
&lt;hr data-end=&quot;487&quot; data-start=&quot;484&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;510&quot; data-start=&quot;489&quot; data-ke-size=&quot;size23&quot;&gt;2. 항해 플러스 참여 계기&lt;/h3&gt;
&lt;p data-end=&quot;603&quot; data-start=&quot;511&quot; data-ke-size=&quot;size16&quot;&gt;하지만 개발자로 일하며 깨달은 것이 있다.&lt;br /&gt;&lt;b&gt;분야도 매우 넓고, 커리어의 방향성을 명확히 잡지 않으면 쉽게 헤맬 수 있다는 것이다.&lt;br /&gt;또한 개발자라고 해서 자연스럽게 실력이 쌓이는 것이 아니라는 점이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;756&quot; data-start=&quot;605&quot; data-ke-size=&quot;size16&quot;&gt;특히나 우리 회사는 전문 IT 기업이 아니다 보니, 성장에 한계가 있음을 느꼈고,&lt;br /&gt;혼자 독학으로 IT 관련 자격증 9개 취득하는 등 나름의 노력을 했지만, 한계가 있었다.&lt;br /&gt;그래서 더 체계적으로 배우고 싶은 마음에 항해99 플러스에 지원하게 되었다.&lt;/p&gt;
&lt;hr data-end=&quot;761&quot; data-start=&quot;758&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;787&quot; data-start=&quot;763&quot; data-ke-size=&quot;size23&quot;&gt;3. 향후 5년 뒤 커리어 방향성&lt;/h3&gt;
&lt;p data-end=&quot;908&quot; data-start=&quot;788&quot; data-ke-size=&quot;size16&quot;&gt;내가 개발자라는 직업에서 가장 매력을 느끼는 부분은 &amp;ldquo;혼자서도 서비스를 만들어 낼 수 있다&amp;rdquo;는 점이다.&lt;br /&gt;사업은 보통 물리적인 공간, 재고, 사람이 필요하다. 하지만 IT 서비스는 상대적으로 훨씬 덜하다.&lt;/p&gt;
&lt;p data-end=&quot;1034&quot; data-start=&quot;910&quot; data-ke-size=&quot;size16&quot;&gt;난 5년 뒤에는 &lt;b&gt;나만의 서비스를 직접 만들었거나, 만들 수 있는 사람&lt;/b&gt;이 되고 싶다.&lt;br /&gt;난 특히 &lt;b&gt;서버리스 아키텍처&lt;/b&gt;에 관심이 많고, 가능한 한 &lt;b&gt;운영과 유지보수가 필요 없는 시스템&lt;/b&gt;을 구축하고 싶다.&lt;/p&gt;
&lt;p data-end=&quot;1121&quot; data-start=&quot;1036&quot; data-ke-size=&quot;size16&quot;&gt;항해에서는 TDD 기반의 개발 방식을 제대로 익혀, &lt;b&gt;배포 전 높은 테스트 커버리지를 확보한 안정적인 서버리스 서비스&lt;/b&gt;를 만드는 것이 목표이다.&lt;/p&gt;
&lt;hr data-end=&quot;1126&quot; data-start=&quot;1123&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1145&quot; data-start=&quot;1128&quot; data-ke-size=&quot;size23&quot;&gt;4. 10주간의 목표&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1474&quot; data-start=&quot;1146&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1242&quot; data-start=&quot;1146&quot;&gt;매주 1회의 WIL작성:&lt;br /&gt;&lt;b&gt;매주 기록하며 생각을 정리하는 습관&lt;/b&gt;을 들이고 싶다.&lt;/li&gt;
&lt;li data-end=&quot;1304&quot; data-start=&quot;1243&quot;&gt;과제는 &lt;b&gt;마감기한 전까지 반드시 제출&lt;/b&gt;:&lt;br /&gt;잘하든 못하든 &lt;b&gt;끝을 &lt;/b&gt;보고 싶다.&lt;/li&gt;
&lt;li data-end=&quot;1474&quot; data-start=&quot;1305&quot;&gt;토요일 오프라인 스터디 전회 참석:&lt;br /&gt;우리팀은 매주 토요일 항해 회의실에서 오프라인 스터디를 진행한다. &lt;b&gt;모든 회차 참석하는 것&lt;/b&gt;을 목표로 하고 있다.&lt;br /&gt;특히 난 발제 의도를 혼자서 온전히 이해하긴 어렵기 때문에, &lt;b&gt;팀원들의 도움이 절실히 필요할 것&lt;/b&gt;이라 생각한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1479&quot; data-start=&quot;1476&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1498&quot; data-start=&quot;1481&quot; data-ke-size=&quot;size23&quot;&gt;5. 최종 목표 배지&lt;/h3&gt;
&lt;p data-end=&quot;1524&quot; data-start=&quot;1499&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;블랙 배지&lt;/b&gt;를 목표로 하려고 한다.&lt;/p&gt;
&lt;p data-end=&quot;1652&quot; data-start=&quot;1526&quot; data-ke-size=&quot;size16&quot;&gt;작년 자격증 공부를 할 땐 &amp;ldquo;커트라인만 넘자&amp;rdquo;는 마음으로 임했다가 탈락하고 n수한 경험이 많았다.&lt;br /&gt;이번 항해에서는 그때의 아쉬움을 반면교사 삼아, &lt;b&gt;처음부터 가장 높은 목표를 잡고 도전하려고 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1652&quot; data-start=&quot;1526&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1652&quot; data-start=&quot;1526&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1652&quot; data-start=&quot;1526&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1652&quot; data-start=&quot;1526&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;항해 추천인코드:NYFKU8&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1652&quot; data-start=&quot;1526&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;20만원 할인 받으세요~&lt;/b&gt;&lt;/p&gt;</description>
      <category>항해+</category>
      <category>TDD</category>
      <category>개발자</category>
      <category>부트캠프</category>
      <category>항해</category>
      <category>항해 추천인코드</category>
      <category>항해+</category>
      <category>항해99</category>
      <author>seuthootdev</author>
      <guid isPermaLink="true">https://seuthootdev.tistory.com/2</guid>
      <comments>https://seuthootdev.tistory.com/2#entry2comment</comments>
      <pubDate>Sat, 5 Jul 2025 23:49:43 +0900</pubDate>
    </item>
  </channel>
</rss>