<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발 공부할래?</title>
    <link>https://loopstudy.tistory.com/</link>
    <description>오늘도 공부하자</description>
    <language>ko</language>
    <pubDate>Fri, 10 Jul 2026 07:15:39 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>loop-study</managingEditor>
    <image>
      <title>개발 공부할래?</title>
      <url>https://tistory1.daumcdn.net/tistory/3969525/attach/caa02b77fe74444788f4b5c402cf63ae</url>
      <link>https://loopstudy.tistory.com</link>
    </image>
    <item>
      <title>23년부터 지금까지 회고</title>
      <link>https://loopstudy.tistory.com/616</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;최근 3년은&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가족의 건강을 돌보는 일에 집중해야 했던 시간이었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;코로나 시기를 지나며 어머니의 기력이 점차 쇠약해지셨고, 이후 알레르기 쇼크(&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;아나필락시스)&lt;/span&gt;와 뇌졸중 등 예기치 못한 위급 상황이 겹치며 보호자로서의 역할을 하게 되었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;다행인 건 작년 늦여름 건강검진에서 문제없고, 평생 먹어야 할 약도 줄인다는 의사의 긍정적인 소견과&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;5&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;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;최소한의 연결고리&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;완전히 개발과 공부에 손을 놓은 듯 보였지만, &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;2021년부터 시작했던 기술 서적 스터디를 2024년 중순까지 꼬박 3년 넘게 이어갔습니다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;각자의 커리어와 개인 사정으로 스터디는 종료가 되었지만, 혼자라도 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;틈틈이&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;기술서적을 읽거나 인강을 수강했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한 트렌드를 놓치지 않기 위해 게개콘, 스프링캠프, 네이버 DAN24 같은 컨퍼런스도 간간이 참여했습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;다시 그리는 지도와 복기의 시간&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-path-to-node=&quot;5&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어머니 건강이 안정되면서 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;다시 시작할 용기를 얻었습니다. 타이밍 좋게 모집을 시작한 '우아한유스방 6기'에 선정된 것은 아주 좋은 기회가 되었습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;하지만 3년이라는 공백은 생각보다 컸고, 무작정 키보드부터 잡기보다는 '무엇을 준비해야 하는가'를 파악하는 것부터 시작했습니다. &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;정확히는 메타인지를 확인했습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;과거에 읽었던 책들을 다시 펼쳐보며, 단순히 '안다'고 착각했던 지식들을 남에게 설명할 수 있는 수준으로 만들기 위한 복기의 시간을 가지려 노력했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;26년 목표는&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;첫번째는 앞으로 공백기 동안 굳어버린 지식들을 완전히 내 것으로 되살리는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;두번째는 바뀐 시장에 맞게 적응하여 백엔드로 취업하는 것입니다.&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&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;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;공백기가 길다보니 주변 사람들의 도움 좀 받아 진행하려 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>목표 및 회고</category>
      <category>26년 목표</category>
      <category>건강이 최고</category>
      <category>뒤늦은 회고록</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/616</guid>
      <comments>https://loopstudy.tistory.com/616#entry616comment</comments>
      <pubDate>Sat, 31 Jan 2026 19:02:08 +0900</pubDate>
    </item>
    <item>
      <title>스프링 시큐리티 - 초기화 과정 이해</title>
      <link>https://loopstudy.tistory.com/515</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인프런 정수원님의 스프링 시큐리티 완전 정복 6.x - 초기화 과정 이해&lt;/b&gt;를 정리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 시큐리티 6.x 이전 버전과 바뀐 점, 앞으로 무엇이 변할지도 설명하시는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 시큐리티 내부 코드까지 다 파헤치면서 &lt;b&gt;매우 자세한 설명을 하시기 때문에 수강하는 걸 추천&lt;/b&gt;한다.&lt;/p&gt;
&lt;figure id=&quot;og_1726730039826&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;스프링 시큐리티 완전 정복 [6.x 개정판] 강의 | 정수원 - 인프런&quot; data-og-description=&quot;정수원 | 스프링 시큐리티 6.x 최신 버전으로 제작된 개정판 강의로 초급에서 중.고급에 이르기까지 스프링 시큐리티의 기본 개념부터 API 사용법과 내부 아키텍처를 학습하게 되고 이를 바탕으&quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://www.inflearn.com/course/스프링-시큐리티-완전정복/dashboard&quot; data-og-url=&quot;https://www.inflearn.com/course/스프링-시큐리티-완전정복&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cf2wTb/hyW6wl8rrb/wgj0dX3R7u5sCqIiEvn5A1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/RTozn/hyW2WmtivH/fpbzKNdF09COHCpFUZwNak/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/c6fQwv/hyW22UwM1v/3s6NE3zaOKPHIE8AFxkkw0/img.png?width=736&amp;amp;height=479&amp;amp;face=0_0_736_479&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/스프링-시큐리티-완전정복/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.inflearn.com/course/스프링-시큐리티-완전정복/dashboard&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cf2wTb/hyW6wl8rrb/wgj0dX3R7u5sCqIiEvn5A1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/RTozn/hyW2WmtivH/fpbzKNdF09COHCpFUZwNak/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/c6fQwv/hyW22UwM1v/3s6NE3zaOKPHIE8AFxkkw0/img.png?width=736&amp;amp;height=479&amp;amp;face=0_0_736_479');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;스프링 시큐리티 완전 정복 [6.x 개정판] 강의 | 정수원 - 인프런&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;정수원 | 스프링 시큐리티 6.x 최신 버전으로 제작된 개정판 강의로 초급에서 중.고급에 이르기까지 스프링 시큐리티의 기본 개념부터 API 사용법과 내부 아키텍처를 학습하게 되고 이를 바탕으&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;프로젝트 구성 및 의존성&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강의를 위한 프로젝트 구성은 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 부트 3.x&lt;/li&gt;
&lt;li&gt;JDK 17&lt;/li&gt;
&lt;li&gt;Gradle - Groovy&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성은 2가지를 추가한다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring Web&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwEijo/btsJGJF2EVW/Fx2BlioEHY9qkyPiMJiTHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwEijo/btsJGJF2EVW/Fx2BlioEHY9qkyPiMJiTHK/img.png&quot; data-alt=&quot;스프링 시큐리티가 추가된 걸 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwEijo/btsJGJF2EVW/Fx2BlioEHY9qkyPiMJiTHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwEijo%2FbtsJGJF2EVW%2FFx2BlioEHY9qkyPiMJiTHK%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;1076&quot; height=&quot;218&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스프링 시큐리티가 추가된 걸 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자동 설정에 의한 보안 기능&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;기본적인 모든 요청에 인증여부를 검증하고 인증이 승인되어야 자원에 접근이 가능하다.&lt;/li&gt;
&lt;li&gt;인증 방식은 FormLogin 방식과 HttpBasic 로그인 방식을 제공한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;인증을 할 수 있는 로그인 페이지가 자동적으로 생성되어 렌더링 된다.&lt;/li&gt;
&lt;li&gt;인증 승인할 수 있게 1개의 계정이 제공된다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;SecurityProperties 설정 클래스에서 생성한다.&lt;/li&gt;
&lt;li&gt;username : user&lt;/li&gt;
&lt;li&gt;password : 랜덤문자열&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXzQG/btsJFrzOKQG/aPSKo2YGcXIkuBPCJidEg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXzQG/btsJFrzOKQG/aPSKo2YGcXIkuBPCJidEg1/img.png&quot; data-alt=&quot;기본으로 제공되는 계정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXzQG/btsJFrzOKQG/aPSKo2YGcXIkuBPCJidEg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXzQG%2FbtsJFrzOKQG%2FaPSKo2YGcXIkuBPCJidEg1%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;1126&quot; height=&quot;620&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기본으로 제공되는 계정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2790&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQp2nh/btsJF5iSHmH/M9DdtKDBtFKEKEIsthQgik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQp2nh/btsJF5iSHmH/M9DdtKDBtFKEKEIsthQgik/img.png&quot; data-alt=&quot;애플리케이션이 실행시 정해지는 패스워드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQp2nh/btsJF5iSHmH/M9DdtKDBtFKEKEIsthQgik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQp2nh%2FbtsJF5iSHmH%2FM9DdtKDBtFKEKEIsthQgik%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;2790&quot; height=&quot;614&quot; data-origin-width=&quot;2790&quot; data-origin-height=&quot;614&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동으로 생성되는 보안 클래스 SpringBootWebSecurityConfiguration 다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 클래스로 SecurityFilterChainConfiguration이 존재하고 @Bean으로 SecurityFilterChain 가 등록되는 걸 알 수 있다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnDefaultWebSecurity
    static class SecurityFilterChainConfiguration {

       @Bean
       @Order(SecurityProperties.BASIC_AUTH_ORDER)
       SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
          http.authorizeHttpRequests((requests) -&amp;gt; requests.anyRequest().authenticated());
          http.formLogin(withDefaults());
          http.httpBasic(withDefaults());
          return http.build();
       }
    }
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈에 등록되는 SecurityFilterChain 코드를 간략하게 설명하자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http.authorizeHttpRequests((requests) -&amp;gt; requests.anyRequest().authenticated()) 코드는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;requests.anyRequest() 모든 요청은 authenticated() 인증을 받게 만드는 내용이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 의미로는 인증이 없으면 자원에 접근할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;formLogin(), httpBasic()는 인증방식을 의미한다.&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;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@RestController
public class IndexController {

    @GetMapping(&quot;/&quot;)
    public String index() {
        return &quot;index&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;localhost:8080/ 로 접근하면 index 문자열이 나와야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1370&quot; data-origin-height=&quot;934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7vS3y/btsJGzRc1Mh/Ke3xurbyvzxjLKQdLNihak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7vS3y/btsJGzRc1Mh/Ke3xurbyvzxjLKQdLNihak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7vS3y/btsJGzRc1Mh/Ke3xurbyvzxjLKQdLNihak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7vS3y%2FbtsJGzRc1Mh%2FKe3xurbyvzxjLKQdLNihak%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;345&quot; height=&quot;235&quot; data-origin-width=&quot;1370&quot; data-origin-height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 localhost:8080/login 로 바뀌면서&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;기본적으로 제공되는 보안 설정 SecurityFilterChain 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제공하는 계정명과 애플리케이션 실행할 때 나오는 랜덤 문자열을 패스워드로 입력하면 인증이 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NM1LQ/btsJFbw7mTe/M3NjDYgzpjVPARfkpTUf0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NM1LQ/btsJFbw7mTe/M3NjDYgzpjVPARfkpTUf0K/img.png&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;462&quot; data-is-animation=&quot;false&quot; width=&quot;549&quot; height=&quot;356&quot; data-widthpercent=&quot;26.51&quot; style=&quot;width: 26.201733%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NM1LQ/btsJFbw7mTe/M3NjDYgzpjVPARfkpTUf0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNM1LQ%2FbtsJFbw7mTe%2FM3NjDYgzpjVPARfkpTUf0K%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;712&quot; height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beLA4d/btsJEN4mUMh/HPNixRjfQ3s6binYMDdKI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beLA4d/btsJEN4mUMh/HPNixRjfQ3s6binYMDdKI1/img.png&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;382&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;73.49&quot; style=&quot;width: 72.635476%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beLA4d/btsJEN4mUMh/HPNixRjfQ3s6binYMDdKI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeLA4d%2FbtsJEN4mUMh%2FHPNixRjfQ3s6binYMDdKI1%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;1632&quot; height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;제공되는 계정으로 인증하여 자원에 접근된 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;SecurityBuilder 와 SecurityConfigurer&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SecurityBuilder는 빌더 클래스로서 웹 보안을 구성하는 빈 객체와 설정클래스들을 생성하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 이를 구현하는 WebSecurity, HttpSecurity가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SecurityBuilder는 인증 및 인가 초기화 작업을 진행하는 SecurityConfigurer를 참조한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - SecurityConfigurer를 통해서 인증 &amp;amp; 인가를 위한 필터를 생성한다.&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public interface SecurityBuilder&amp;lt;O&amp;gt; {

    /**
     * Builds the object and returns it or null.
     * @return the Object to be built or null if the implementation allows it.
     * @throws Exception if an error occurred when building the Object
     */
    O build() throws Exception;

}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public interface SecurityConfigurer&amp;lt;O, B extends SecurityBuilder&amp;lt;O&amp;gt;&amp;gt; {

    /**
     * Initialize the {@link SecurityBuilder}. Here only shared state should be created
     * and modified, but not properties on the {@link SecurityBuilder} used for building
     * the object. This ensures that the {@link #configure(SecurityBuilder)} method uses
     * the correct shared objects when building. Configurers should be applied here.
     * @param builder
     * @throws Exception
     */
    void init(B builder) throws Exception;

    /**
     * Configure the {@link SecurityBuilder} by setting the necessary properties on the
     * {@link SecurityBuilder}.
     * @param builder
     * @throws Exception
     */
    void configure(B builder) throws Exception;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q0BxJ/btsJGXeHjKb/39tfr20I8QozkbbZ3Qz7WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q0BxJ/btsJGXeHjKb/39tfr20I8QozkbbZ3Qz7WK/img.png&quot; data-origin-width=&quot;2178&quot; data-origin-height=&quot;900&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;83.28&quot; style=&quot;width: 82.314393%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q0BxJ/btsJGXeHjKb/39tfr20I8QozkbbZ3Qz7WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ0BxJ%2FbtsJGXeHjKb%2F39tfr20I8QozkbbZ3Qz7WK%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;2178&quot; height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DiefI/btsJIfebfOq/k0RkxTvpTWDkdi8ObNtdEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DiefI/btsJIfebfOq/k0RkxTvpTWDkdi8ObNtdEk/img.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;1194&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;16.72&quot; style=&quot;width: 16.522817%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DiefI/btsJIfebfOq/k0RkxTvpTWDkdi8ObNtdEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDiefI%2FbtsJIfebfOq%2Fk0RkxTvpTWDkdi8ObNtdEk%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;580&quot; height=&quot;1194&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;SecurityBuilder, SecurityConfigurer와 구현체들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실행 과정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적인 흐름은 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;스프링부트 AutoConfiguration을 통해 SecurityBuilder를 생성한다.&lt;/li&gt;
&lt;li&gt;SecurityBuilder는 설정클래스인 SecurityConfigurer를 생성한다.&lt;/li&gt;
&lt;li&gt;SecurityConfigurer의 init(), configure() 로 초기화 작업을 진행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;HttpSecurity 코드로 보는 과정&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2246&quot; data-origin-height=&quot;924&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKhPDW/btsJQjN3CqS/YCP7qtJAEJy8MMMq9QrBsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKhPDW/btsJQjN3CqS/YCP7qtJAEJy8MMMq9QrBsK/img.png&quot; data-alt=&quot;HttpSecurity 생성과 인증 및 인가의 초기화 과정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKhPDW/btsJQjN3CqS/YCP7qtJAEJy8MMMq9QrBsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKhPDW%2FbtsJQjN3CqS%2FYCP7qtJAEJy8MMMq9QrBsK%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;2246&quot; height=&quot;924&quot; data-origin-width=&quot;2246&quot; data-origin-height=&quot;924&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;HttpSecurity 생성과 인증 및 인가의 초기화 과정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HttpSecurity 빈을 생성하고 인증 및 인가를 설정하는 건 HttpSecurityConfiguration 클래스다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration(proxyBeanMethods = false)
class HttpSecurityConfiguration {
...
	@Bean(HTTPSECURITY_BEAN_NAME)
	@Scope(&quot;prototype&quot;)
	HttpSecurity httpSecurity() throws Exception {
		LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
		AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(
				this.objectPostProcessor, passwordEncoder);
		authenticationBuilder.parentAuthenticationManager(authenticationManager());
		authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
		HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
		WebAsyncManagerIntegrationFilter webAsyncManagerIntegrationFilter = new WebAsyncManagerIntegrationFilter();
		webAsyncManagerIntegrationFilter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
		// @formatter:off
		http
			.csrf(withDefaults())
			.addFilter(webAsyncManagerIntegrationFilter)
			.exceptionHandling(withDefaults())
			.headers(withDefaults())
			.sessionManagement(withDefaults())
			.securityContext(withDefaults())
			.requestCache(withDefaults())
			.anonymous(withDefaults())
			.servletApi(withDefaults())
			.apply(new DefaultLoginPageConfigurer&amp;lt;&amp;gt;());
		http.logout(withDefaults());
		// @formatter:on
		applyCorsIfAvailable(http);
		applyDefaultConfigurers(http);
		return http;
	}
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 살펴보면 빈 스코프가 &amp;nbsp;프로토타입으로 생성하는데 별도의 보안 설정을 위해서다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증 및 인가에 관한 설정은 // @formatter 주석으로 구분되는 영역이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 설정된 인증 및 인가는 10개다. &lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;각 설정에 대한 내용은 추후 강의로 배움&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1727430203087&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// @formatter:off
http
    .csrf(withDefaults())
    .addFilter(webAsyncManagerIntegrationFilter)
    .exceptionHandling(withDefaults())
    .headers(withDefaults())
    .sessionManagement(withDefaults())
    .securityContext(withDefaults())
    .requestCache(withDefaults())
    .anonymous(withDefaults())
    .servletApi(withDefaults())
    .apply(new DefaultLoginPageConfigurer&amp;lt;&amp;gt;());
http.logout(withDefaults());
// @formatter:on&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;986&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mQd7x/btsJOMdujSy/AKh5aYFoxhGxwUafoQJVi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mQd7x/btsJOMdujSy/AKh5aYFoxhGxwUafoQJVi1/img.png&quot; data-alt=&quot;SecurityConfigurer를 상속받아 구현한 csrf 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mQd7x/btsJOMdujSy/AKh5aYFoxhGxwUafoQJVi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmQd7x%2FbtsJOMdujSy%2FAKh5aYFoxhGxwUafoQJVi1%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;1570&quot; height=&quot;986&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;986&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SecurityConfigurer를 상속받아 구현한 csrf 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1878&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drg6WW/btsJPoWHqaO/RKRHz0MdnkNMZIHmyYwtp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drg6WW/btsJPoWHqaO/RKRHz0MdnkNMZIHmyYwtp1/img.png&quot; data-alt=&quot;httpSecurityConfiguration 에서 생성된 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drg6WW/btsJPoWHqaO/RKRHz0MdnkNMZIHmyYwtp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdrg6WW%2FbtsJPoWHqaO%2FRKRHz0MdnkNMZIHmyYwtp1%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;1878&quot; height=&quot;440&quot; data-origin-width=&quot;1878&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;httpSecurityConfiguration 에서 생성된 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;※ DefaultLoginPageConfigurer는 자동으로 로그인 페이지를 생성해 준다.&lt;br /&gt;※ 강의에서는 설정이 11개 생성되는데, 버전 차이인지 CorsConfigurer 설정 없이 생성되었다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생성된 빈은 SpringBootWebSecurityConfiguration에서 사용된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SpringBootWebSecurityConfiguration&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 생성된 HttpSecurity 빈을 받아서 설정을 더 추가하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 build()를 통해 SecurityFilterChain 생성해서 빈으로 등록한다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnDefaultWebSecurity
	static class SecurityFilterChainConfiguration {

		@Bean
		@Order(SecurityProperties.BASIC_AUTH_ORDER)
		SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
			http.authorizeHttpRequests((requests) -&amp;gt; requests.anyRequest().authenticated());
			http.formLogin(withDefaults());
			http.httpBasic(withDefaults());
			return http.build();
		}
	}
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1932&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L7G02/btsJQaxed4Y/Tf3NlZ9OFpEbASeykVpYC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L7G02/btsJQaxed4Y/Tf3NlZ9OFpEbASeykVpYC1/img.png&quot; data-alt=&quot;리스트 마지막에 설정 3개가 추가된 걸 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L7G02/btsJQaxed4Y/Tf3NlZ9OFpEbASeykVpYC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL7G02%2FbtsJQaxed4Y%2FTf3NlZ9OFpEbASeykVpYC1%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;1932&quot; height=&quot;564&quot; data-origin-width=&quot;1932&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;리스트 마지막에 설정 3개가 추가된 걸 확인할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http.build() 코드를 따라가 보면 doBuild()가 실행되는데 코드를 간단히 설명하자면&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;init() : 각 configure의 초기화 작업을 진행한다&lt;/li&gt;
&lt;li&gt;configure() : 보안 설정을 적용한다.&lt;/li&gt;
&lt;li&gt;performBuild() : SecurityFilterChain를 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public abstract class AbstractConfiguredSecurityBuilder&amp;lt;O, B extends SecurityBuilder&amp;lt;O&amp;gt;&amp;gt;
       extends AbstractSecurityBuilder&amp;lt;O&amp;gt; {
...
	@Override
	protected final O doBuild() throws Exception {
		synchronized (this.configurers) {
			this.buildState = BuildState.INITIALIZING;
			beforeInit();
			init();
			this.buildState = BuildState.CONFIGURING;
			beforeConfigure();
			configure();
			this.buildState = BuildState.BUILDING;
			O result = performBuild();
			this.buildState = BuildState.BUILT;
			return result;
		}
	}
    
	/**
	 * Subclasses must implement this method to build the object that is being returned.
	 * @return the Object to be buit or null if the implementation allows it
	 */
	protected abstract O performBuild() throws Exception;
    
	@SuppressWarnings(&quot;unchecked&quot;)
	private void init() throws Exception {
		Collection&amp;lt;SecurityConfigurer&amp;lt;O, B&amp;gt;&amp;gt; configurers = getConfigurers();
		for (SecurityConfigurer&amp;lt;O, B&amp;gt; configurer : configurers) {
			configurer.init((B) this);
		}
		for (SecurityConfigurer&amp;lt;O, B&amp;gt; configurer : this.configurersAddedInInitializing) {
			configurer.init((B) this);
		}
	}

	@SuppressWarnings(&quot;unchecked&quot;)
	private void configure() throws Exception {
		Collection&amp;lt;SecurityConfigurer&amp;lt;O, B&amp;gt;&amp;gt; configurers = getConfigurers();
		for (SecurityConfigurer&amp;lt;O, B&amp;gt; configurer : configurers) {
			configurer.configure((B) this);
		}
	}
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ejKYDr/btsJO0pcwiM/6PG8pRqkGfqGAK7CTWE7wK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ejKYDr/btsJO0pcwiM/6PG8pRqkGfqGAK7CTWE7wK/img.png&quot; data-alt=&quot;HttpSecurity에서 생성하는 SecurityFilterChain&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ejKYDr/btsJO0pcwiM/6PG8pRqkGfqGAK7CTWE7wK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FejKYDr%2FbtsJO0pcwiM%2F6PG8pRqkGfqGAK7CTWE7wK%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;1492&quot; height=&quot;700&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;HttpSecurity에서 생성하는 SecurityFilterChain&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 HttpSecurity.build() 과정은 SecurityFilterChain를 생성하고 반환하는 것으로 마무리된다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;b&gt;HttpSecurity&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- HttpSecurityConfiguration에서 HttpSecurity를 생성하고 초기화를 진행함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- HttpSecurity는 보안에 필요한 각 설정 클래스와 필터들을 생성하고 &lt;b&gt;최종적으로 SecurityFilterChain 빈을 생성&lt;/b&gt;함.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1574&quot; data-origin-height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxwNM4/btsJPciLTU8/L07tWK2CNdhwb5AFowtkj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxwNM4/btsJPciLTU8/L07tWK2CNdhwb5AFowtkj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxwNM4/btsJPciLTU8/L07tWK2CNdhwb5AFowtkj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxwNM4%2FbtsJPciLTU8%2FL07tWK2CNdhwb5AFowtkj0%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;1574&quot; height=&quot;562&quot; data-origin-width=&quot;1574&quot; data-origin-height=&quot;562&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SecurityFilterChain&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;866&quot; data-origin-height=&quot;782&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ym5X6/btsJPUhdeEK/Lz99Ovxw8HwirI3E5UK5b1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ym5X6/btsJPUhdeEK/Lz99Ovxw8HwirI3E5UK5b1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ym5X6/btsJPUhdeEK/Lz99Ovxw8HwirI3E5UK5b1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fym5X6%2FbtsJPUhdeEK%2FLz99Ovxw8HwirI3E5UK5b1%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;376&quot; height=&quot;782&quot; data-origin-width=&quot;866&quot; data-origin-height=&quot;782&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;boolean matches(HttpServletRequest request)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 요청이 현재 필터 체인에 의해 처리되는지 여부를 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- true 반환하면 해당 필터 체인에 처리됨을 의미하고, false를 반환하면 다른 처리 로직이 처리됨을 의미한다.&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;List&amp;lt;Filter&amp;gt; getFilters()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 현재 필터 체인에 포함된 Filter 객체의 리스트를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 어떤 필터들이 포함되어 있는지 확인할 수 있고, 각 필터는 요청 처리 과정에서 특정 작업(인증, 권한 부여, 로깅 등)을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;b&gt;WebSecurity&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- WebSecurityConfiguration에서 WebSecurity를 생성하고 초기화를 진행함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- WebSecurity는 HttpSecurity에서 생성한 SecurityFilterChain 빈을 SecurityBuilder 에 저장함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- WebSecurity가 build()를 실행하면 SecurityBuilder에서 SecurityFilterChain을 꺼내어 FilterChainProxy 생성자에 전달함.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC2IkO/btsJQmSmAru/ZK7u1eIpXZAnqNPjZxMzeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC2IkO/btsJQmSmAru/ZK7u1eIpXZAnqNPjZxMzeK/img.png&quot; data-alt=&quot;HttpSecurity와 똑같은 패턴이다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC2IkO/btsJQmSmAru/ZK7u1eIpXZAnqNPjZxMzeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC2IkO%2FbtsJQmSmAru%2FZK7u1eIpXZAnqNPjZxMzeK%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;1570&quot; height=&quot;716&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;716&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;HttpSecurity와 똑같은 패턴이다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;코드로 보는 WebSecurity&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebSecurityConfiguration에서 살펴볼 코드 일부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디버깅으로 흐름을 파악해 보면 HttpSecurity를 통해 SecurityFilterChain 빈이 생성된 후 이를 WebSecurity에서 FilterChainProxy 생성하는 것을 볼 수 있다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
...
	/**
	 * Creates the Spring Security Filter Chain
	 * @return the {@link Filter} that represents the security filter chain
	 * @throws Exception
	 */
	@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
	public Filter springSecurityFilterChain() throws Exception {
		boolean hasFilterChain = !this.securityFilterChains.isEmpty();
		if (!hasFilterChain) {
			this.webSecurity.addSecurityFilterChainBuilder(() -&amp;gt; {
				this.httpSecurity.authorizeHttpRequests((authorize) -&amp;gt; authorize.anyRequest().authenticated());
				this.httpSecurity.formLogin(Customizer.withDefaults());
				this.httpSecurity.httpBasic(Customizer.withDefaults());
				return this.httpSecurity.build();
			});
		}
		for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
			this.webSecurity.addSecurityFilterChainBuilder(() -&amp;gt; securityFilterChain);
		}
		for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
			customizer.customize(this.webSecurity);
		}
		return this.webSecurity.build();
	}
    

	/**
	 * Sets the {@code &amp;lt;SecurityConfigurer&amp;lt;FilterChainProxy, WebSecurityBuilder&amp;gt;}
	 * instances used to create the web configuration.
	 * @param objectPostProcessor the {@link ObjectPostProcessor} used to create a
	 * {@link WebSecurity} instance
	 * @param beanFactory the bean factory to use to retrieve the relevant
	 * {@code &amp;lt;SecurityConfigurer&amp;lt;FilterChainProxy, WebSecurityBuilder&amp;gt;} instances used to
	 * create the web configuration
	 * @throws Exception
	 */
	@Autowired(required = false)
	public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor&amp;lt;Object&amp;gt; objectPostProcessor,
			ConfigurableListableBeanFactory beanFactory) throws Exception {
		this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
		if (this.debugEnabled != null) {
			this.webSecurity.debug(this.debugEnabled);
		}
		List&amp;lt;SecurityConfigurer&amp;lt;Filter, WebSecurity&amp;gt;&amp;gt; webSecurityConfigurers = new AutowiredWebSecurityConfigurersIgnoreParents(
				beanFactory)
			.getWebSecurityConfigurers();
		webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
		Integer previousOrder = null;
		Object previousConfig = null;
		for (SecurityConfigurer&amp;lt;Filter, WebSecurity&amp;gt; config : webSecurityConfigurers) {
			Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
			if (previousOrder != null &amp;amp;&amp;amp; previousOrder.equals(order)) {
				throw new IllegalStateException(&quot;@Order on WebSecurityConfigurers must be unique. Order of &quot; + order
						+ &quot; was already used on &quot; + previousConfig + &quot;, so it cannot be used on &quot; + config + &quot; too.&quot;);
			}
			previousOrder = order;
			previousConfig = config;
		}
		for (SecurityConfigurer&amp;lt;Filter, WebSecurity&amp;gt; webSecurityConfigurer : webSecurityConfigurers) {
			this.webSecurity.apply(webSecurityConfigurer);
		}
		this.webSecurityConfigurers = webSecurityConfigurers;
	}

	@Autowired(required = false)
	void setFilterChains(List&amp;lt;SecurityFilterChain&amp;gt; securityFilterChains) {
		this.securityFilterChains = securityFilterChains;
	}

    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkf1YV/btsJPNC4Fh5/9eYhdRtvQgPX6vWkMxXfQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkf1YV/btsJPNC4Fh5/9eYhdRtvQgPX6vWkMxXfQk/img.png&quot; data-alt=&quot;SecurityFilterChain 빈을 주입받는 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkf1YV/btsJPNC4Fh5/9eYhdRtvQgPX6vWkMxXfQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbkf1YV%2FbtsJPNC4Fh5%2F9eYhdRtvQgPX6vWkMxXfQk%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;1690&quot; height=&quot;298&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SecurityFilterChain 빈을 주입받는 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1438&quot; data-origin-height=&quot;818&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s109l/btsJQiicHD7/KCD8LS6cc65cdNMUpO97AK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s109l/btsJQiicHD7/KCD8LS6cc65cdNMUpO97AK/img.png&quot; data-alt=&quot;최종적으로 FilterChainProxy를 빈으로 등록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s109l/btsJQiicHD7/KCD8LS6cc65cdNMUpO97AK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs109l%2FbtsJQiicHD7%2FKCD8LS6cc65cdNMUpO97AK%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;1438&quot; height=&quot;818&quot; data-origin-width=&quot;1438&quot; data-origin-height=&quot;818&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;최종적으로 FilterChainProxy를 빈으로 등록&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k4jlP/btsJQ6bLKB6/kWN6cKlXQLoHkgzgD49ZBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k4jlP/btsJQ6bLKB6/kWN6cKlXQLoHkgzgD49ZBk/img.png&quot; data-alt=&quot;FilterChainProxy의 이름은 springSecurityFilterChain&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k4jlP/btsJQ6bLKB6/kWN6cKlXQLoHkgzgD49ZBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk4jlP%2FbtsJQ6bLKB6%2FkWN6cKlXQLoHkgzgD49ZBk%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;1902&quot; height=&quot;226&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;226&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;FilterChainProxy의 이름은 springSecurityFilterChain&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caZD9t/btsJRoIy8Cr/kaQoOTMewLzHyO0W6iVC6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caZD9t/btsJRoIy8Cr/kaQoOTMewLzHyO0W6iVC6k/img.png&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;864&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;38.46&quot; style=&quot;width: 38.012532%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caZD9t/btsJRoIy8Cr/kaQoOTMewLzHyO0W6iVC6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaZD9t%2FbtsJRoIy8Cr%2FkaQoOTMewLzHyO0W6iVC6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1520&quot; height=&quot;864&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EVOxi/btsJRdtGpOo/3y3kucJqOsFfV96eBfEHq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EVOxi/btsJRdtGpOo/3y3kucJqOsFfV96eBfEHq0/img.png&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;346&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;61.54&quot; style=&quot;width: 60.824677%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EVOxi/btsJRdtGpOo/3y3kucJqOsFfV96eBfEHq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEVOxi%2FbtsJRdtGpOo%2F3y3kucJqOsFfV96eBfEHq0%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;974&quot; height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;WebSecurity.performBuild()로 생성된 FilterChainProxy&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Filter&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 서블릿 필터는 웹 애플리케이션에서 클라이언트의 요청과 서버의 응답을 가공하거나 검사하는 데 사용되는 구성 요소다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 서블릿 필터는 클라이언트의 요청이 서블릿에 도달하기 전이나 서블릿이 응답을 클라이언트에게 보내기 전에 특정 작업을 수행할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 서블릿 필터는 서블릿 컨테이너(WAS)에서 생성되고 실행되고 종료된다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;DelegatingFilterProxy&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 스프링에서 사용하는 특별한 서블릿 필터로, 서블릿 컨테이너와 스프링 애플리케이션 컨텍스트 간의 연결고리 역할을 하는 필터다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 서블릿 필터의 기능을 수행하는 동시에 스프링의 의존성 주입 및 빈 관리 기능과 연동되도록 설계된 필터다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- &lt;b&gt;springSecurityFilterChain&lt;/b&gt; 이름으로 생성된 빈을 ApplicationContext에서 찾아 요청을 위임한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 실제 보안 처리를 수행하지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2V559/btsJRbW0yge/aPjCRKUdjUYzxfSDUYvgo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2V559/btsJRbW0yge/aPjCRKUdjUYzxfSDUYvgo0/img.png&quot; data-alt=&quot;DelegatingFilterProxy 서블릿 필터의 요청 위임&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2V559/btsJRbW0yge/aPjCRKUdjUYzxfSDUYvgo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2V559%2FbtsJRbW0yge%2FaPjCRKUdjUYzxfSDUYvgo0%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;1434&quot; height=&quot;724&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DelegatingFilterProxy 서블릿 필터의 요청 위임&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;FilterChainProxy&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- springSecurityFilterChain의 이름으로 생성되는 필터 빈으로서 DelegatingFilterProxy 에게 요청을 위임받고 보안 처리 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 내부적으로 하나 이상의 SecurityFilterChain 객체들을 가지고 있으며 요청 URL 정보를 기준으로 적절한 SecurityFilterChain를 선택하여 필터들을 호출한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- HttpSecurity 를 통해 API 추가 시 관련 필터들을 추가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 사용자의 요청을 필터 순서대로 호출함으로 보안 기능을 동작시키고 필요시 직접 필터를 생성해서 기존 필터의 전, 후로 추가 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;1040&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buKtz1/btsJUDMIbIY/yJRhdPMtpmvGF26XPaIHv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buKtz1/btsJUDMIbIY/yJRhdPMtpmvGF26XPaIHv1/img.png&quot; data-alt=&quot;필터 순서대로 처리된다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buKtz1/btsJUDMIbIY/yJRhdPMtpmvGF26XPaIHv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuKtz1%2FbtsJUDMIbIY%2FyJRhdPMtpmvGF26XPaIHv1%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;467&quot; height=&quot;534&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;1040&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;필터 순서대로 처리된다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSdUCD/btsJRqVpJTF/vK3tV6Og2mhei6ZOauRQMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSdUCD/btsJRqVpJTF/vK3tV6Og2mhei6ZOauRQMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSdUCD/btsJRqVpJTF/vK3tV6Og2mhei6ZOauRQMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSdUCD%2FbtsJRqVpJTF%2FvK3tV6Og2mhei6ZOauRQMk%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;1538&quot; height=&quot;724&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;724&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;코드로 보는 DelegatingFilterProxy 생성 과정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션이 실행되면 SecurityFilterAutoConfiguration에서 자동으로 빈을 생성하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ConditionalOnBean 으로 springSecurityFilterChain 빈이 있어야 생성되는 걸 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1840&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lgP8O/btsJTzEFxto/3CyltrJS1t0GbM5cbXvW70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lgP8O/btsJTzEFxto/3CyltrJS1t0GbM5cbXvW70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lgP8O/btsJTzEFxto/3CyltrJS1t0GbM5cbXvW70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlgP8O%2FbtsJTzEFxto%2F3CyltrJS1t0GbM5cbXvW70%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;1840&quot; height=&quot;800&quot; data-origin-width=&quot;1840&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1848&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dz21I/btsJUi3hjsm/oupg7zqfkzKDs8lkiQ31Pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dz21I/btsJUi3hjsm/oupg7zqfkzKDs8lkiQ31Pk/img.png&quot; data-alt=&quot;@ConditionalOnBean이 찾는 springSecurityFilterChain&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dz21I/btsJUi3hjsm/oupg7zqfkzKDs8lkiQ31Pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDz21I%2FbtsJUi3hjsm%2Foupg7zqfkzKDs8lkiQ31Pk%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;1848&quot; height=&quot;254&quot; data-origin-width=&quot;1848&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;@ConditionalOnBean이 찾는 springSecurityFilterChain&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq7rkn/btsJToXyDvB/vnfNNx3roRaPHKKUuKBwh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq7rkn/btsJToXyDvB/vnfNNx3roRaPHKKUuKBwh1/img.png&quot; data-alt=&quot;위임을 위한 타겟명 springSecurityFilterChain&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq7rkn/btsJToXyDvB/vnfNNx3roRaPHKKUuKBwh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq7rkn%2FbtsJToXyDvB%2FvnfNNx3roRaPHKKUuKBwh1%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;1826&quot; height=&quot;868&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;868&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위임을 위한 타겟명 springSecurityFilterChain&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1810&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hbjtd/btsJSMR3U9Q/0hR5EATWpBlt7LlEpqiHs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hbjtd/btsJSMR3U9Q/0hR5EATWpBlt7LlEpqiHs0/img.png&quot; data-alt=&quot;서블릿 필터에 추가되는 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hbjtd/btsJSMR3U9Q/0hR5EATWpBlt7LlEpqiHs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHbjtd%2FbtsJSMR3U9Q%2F0hR5EATWpBlt7LlEpqiHs0%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;1810&quot; height=&quot;304&quot; data-origin-width=&quot;1810&quot; data-origin-height=&quot;304&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FIlterChainProxy 생성은 위의 &lt;b&gt;코드로 보는 WebSecurity &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;&lt;b&gt;실습으로 보는 작동 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디버깅 모드로 애플리케이션을 실행하고 자원에 접근하면 DelegatingFilterProxy이 어떻게 작동하는지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무 자원이나 요청하면 서블릿 필터인 DelegatingFilterProxy를 무조건 거치게 되어있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bimqEl/btsJUmYIrLZ/YbyhuWKS0h371ed8X3f7XK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bimqEl/btsJUmYIrLZ/YbyhuWKS0h371ed8X3f7XK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bimqEl/btsJUmYIrLZ/YbyhuWKS0h371ed8X3f7XK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbimqEl%2FbtsJUmYIrLZ%2FYbyhuWKS0h371ed8X3f7XK%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;1806&quot; height=&quot;766&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;1120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF1wc8/btsJS7u1QXA/gCLXKEmgMAUYqeyXHdnqAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF1wc8/btsJS7u1QXA/gCLXKEmgMAUYqeyXHdnqAK/img.png&quot; data-alt=&quot;delegate는 최초에 한번만 생성된 후 호출만된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF1wc8/btsJS7u1QXA/gCLXKEmgMAUYqeyXHdnqAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF1wc8%2FbtsJS7u1QXA%2FgCLXKEmgMAUYqeyXHdnqAK%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;1804&quot; height=&quot;1120&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;1120&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;delegate는 최초에 한번만 생성된 후 호출만된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1798&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eVAtnY/btsJUFqeH9m/XhJCoYylk0nwiSsYtplx70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eVAtnY/btsJUFqeH9m/XhJCoYylk0nwiSsYtplx70/img.png&quot; data-alt=&quot;스프링 컨테이너부터 빈을 찾는 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eVAtnY/btsJUFqeH9m/XhJCoYylk0nwiSsYtplx70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeVAtnY%2FbtsJUFqeH9m%2FXhJCoYylk0nwiSsYtplx70%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;1798&quot; height=&quot;494&quot; data-origin-width=&quot;1798&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스프링 컨테이너부터 빈을 찾는 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1744&quot; data-origin-height=&quot;1004&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cD5g1a/btsJTU2JfWa/kh86zHIbUJ9RgdGtuFUSG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cD5g1a/btsJTU2JfWa/kh86zHIbUJ9RgdGtuFUSG1/img.png&quot; data-alt=&quot;찾은 springSecurityFilterChain&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cD5g1a/btsJTU2JfWa/kh86zHIbUJ9RgdGtuFUSG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcD5g1a%2FbtsJTU2JfWa%2Fkh86zHIbUJ9RgdGtuFUSG1%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;1744&quot; height=&quot;1004&quot; data-origin-width=&quot;1744&quot; data-origin-height=&quot;1004&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;찾은 springSecurityFilterChain&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1810&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MdE0c/btsJT78Jk90/IB3jCNzTb6Crulnta8wFuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MdE0c/btsJT78Jk90/IB3jCNzTb6Crulnta8wFuK/img.png&quot; data-alt=&quot;찾아온 FilterChainProxy를 호출하는 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MdE0c/btsJT78Jk90/IB3jCNzTb6Crulnta8wFuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMdE0c%2FbtsJT78Jk90%2FIB3jCNzTb6Crulnta8wFuK%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;1810&quot; height=&quot;420&quot; data-origin-width=&quot;1810&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;찾아온 FilterChainProxy를 호출하는 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;1216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rNCW3/btsJSPH0vlk/IH2zJMwuN0KMKAniQd9CO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rNCW3/btsJSPH0vlk/IH2zJMwuN0KMKAniQd9CO1/img.png&quot; data-alt=&quot;FilterChainProxy에서 돌아가는 필터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rNCW3/btsJSPH0vlk/IH2zJMwuN0KMKAniQd9CO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrNCW3%2FbtsJSPH0vlk%2FIH2zJMwuN0KMKAniQd9CO1%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;1800&quot; height=&quot;1216&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;1216&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;FilterChainProxy에서 돌아가는 필터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FilterChainProxy 내부에는 VirtualFilterChain이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 필터가 0번부터 마지막까지 순서대로 수행된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMRyvv/btsJUZhCdN1/cLQxsSUvxa7Cd76dXU6XNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMRyvv/btsJUZhCdN1/cLQxsSUvxa7Cd76dXU6XNK/img.png&quot; data-origin-width=&quot;1808&quot; data-origin-height=&quot;1394&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.72&quot; style=&quot;width: 49.13935%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMRyvv/btsJUZhCdN1/cLQxsSUvxa7Cd76dXU6XNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMRyvv%2FbtsJUZhCdN1%2FcLQxsSUvxa7Cd76dXU6XNK%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;1808&quot; height=&quot;1394&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KZt28/btsJVbhUU0i/4tkATb7wg1zIg8kYmyysJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KZt28/btsJVbhUU0i/4tkATb7wg1zIg8kYmyysJK/img.png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;648&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50.28&quot; style=&quot;width: 49.697859%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KZt28/btsJVbhUU0i/4tkATb7wg1zIg8kYmyysJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKZt28%2FbtsJVbhUU0i%2F4tkATb7wg1zIg8kYmyysJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;850&quot; height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;필터 0번부터 마지막까지 수행되는 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qBQBy/btsJSQGYZfQ/vmkMeI8kk7pdqROHFGXWc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qBQBy/btsJSQGYZfQ/vmkMeI8kk7pdqROHFGXWc0/img.png&quot; data-alt=&quot;인증이 없어 login 으로 재요청되는 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qBQBy/btsJSQGYZfQ/vmkMeI8kk7pdqROHFGXWc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqBQBy%2FbtsJSQGYZfQ%2FvmkMeI8kk7pdqROHFGXWc0%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;1660&quot; height=&quot;750&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;750&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인증이 없어 login 으로 재요청되는 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;사용자 정의 보안 기능 구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 정의하는 보안 기능 구현은 한 개 이상의 SecurityFilterChain 타입의 빈을 정의한 후 인증 API 및 인가 API 를 설정한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm9tdy/btsJUPTQqxs/lTAikwAcsf0Up5X5Qre6WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm9tdy/btsJUPTQqxs/lTAikwAcsf0Up5X5Qre6WK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm9tdy/btsJUPTQqxs/lTAikwAcsf0Up5X5Qre6WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm9tdy%2FbtsJUPTQqxs%2FlTAikwAcsf0Up5X5Qre6WK%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;1222&quot; height=&quot;772&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;772&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기본 구현 코드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@EnableWebSecuriy를 선언해 줘야 자동 설정으로 어노테이션 안에 있는 여러 가지 설정이 초기화된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;사용자 정의로 SecurityFilterChain 빈을 생성하면 자동 설정에 의한 SecurityFilterChain 빈은 생성되지 않는다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;b&gt;모든 설정 코드는 람다 형식으로 작성해야 한다 (스프링 시큐리티 7 버전부터는 람다 형식만 지원 예정)&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@EnableWebSecurity
@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests(auth -&amp;gt; auth.anyRequest().authenticated())
            .formLogin(Customizer.withDefaults());

        return http.build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
       HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
public @interface EnableWebSecurity {

    /**
     * Controls debugging support for Spring Security. Default is false.
     * @return if true, enables debug support with Spring Security
     */
    boolean debug() default false;

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 설정으로 기본으로 제공되는 SecurityFilterChain 빈은 @ConditionalOnMissingBean 으로 더 이상 생성되지 않는다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class DefaultWebSecurityCondition extends AllNestedConditions {

    DefaultWebSecurityCondition() {
       super(ConfigurationPhase.REGISTER_BEAN);
    }

    @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
    static class Classes {

    }

    @ConditionalOnMissingBean({ SecurityFilterChain.class })
    static class Beans {

    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;사용자 추가 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본으로 제공하는 사용자 정보도 application.properties 혹은 application.yml 파일로 정의할 수 있다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;spring:
  security:
    user:
      name: user
      password: 1111
      roles: USER&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 설정 클래스에서 직접 정의도 가능하다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; text-align: start;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Bean
public UserDetailsService userDetailsService() {
    UserDetails user = User.withUsername(&quot;user&quot;)
            .password(&quot;{noop}1111&quot;)
            .roles(&quot;USER&quot;)
            .build();

    UserDetails user2 = User.withUsername(&quot;user2&quot;)
            .password(&quot;{noop}1111&quot;)
            .roles(&quot;USER&quot;)
            .build();

    UserDetails user3 = User.withUsername(&quot;user3&quot;)
            .password(&quot;{noop}1111&quot;)
            .roles(&quot;USER&quot;)
            .build();
    return new InMemoryUserDetailsManager(user, user2, user3);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;838&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cR0MOO/btsJUkUWRbb/nCgrftoymMwvBZBI715wyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cR0MOO/btsJUkUWRbb/nCgrftoymMwvBZBI715wyk/img.png&quot; data-alt=&quot;직접 설정한 사용자 추가 후 기본으로 제공되는 사용자 정보는 찾아볼 수가 없다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cR0MOO/btsJUkUWRbb/nCgrftoymMwvBZBI715wyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcR0MOO%2FbtsJUkUWRbb%2FnCgrftoymMwvBZBI715wyk%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;2144&quot; height=&quot;838&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;838&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbUlpl/btsJUpIBoDP/KalLXfibLQwybk670NCH50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbUlpl/btsJUpIBoDP/KalLXfibLQwybk670NCH50/img.png&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;488&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;56.03&quot; style=&quot;width: 55.380935%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbUlpl/btsJUpIBoDP/KalLXfibLQwybk670NCH50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbUlpl%2FbtsJUpIBoDP%2FKalLXfibLQwybk670NCH50%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;738&quot; height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vzi2O/btsJTJud7TV/365U6GCvPprQsjZlMDiMU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vzi2O/btsJTJud7TV/365U6GCvPprQsjZlMDiMU1/img.png&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;300&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;43.97&quot; style=&quot;width: 43.456274%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vzi2O/btsJTJud7TV/365U6GCvPprQsjZlMDiMU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVzi2O%2FbtsJTJud7TV%2F365U6GCvPprQsjZlMDiMU1%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;356&quot; height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;직접 설정한 사용자로 인증이 된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>교육 및 인강/스프링 시큐리티 완전정복 6.x</category>
      <category>DelegatingFilterProxy</category>
      <category>FilterChainProxy</category>
      <category>security</category>
      <category>securitybuilder</category>
      <category>securityconfigurer</category>
      <category>Spring Security</category>
      <category>스프링 시큐리티</category>
      <category>시큐리티</category>
      <category>정수원</category>
      <category>초기화 과정</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/515</guid>
      <comments>https://loopstudy.tistory.com/515#entry515comment</comments>
      <pubDate>Fri, 4 Oct 2024 13:39:19 +0900</pubDate>
    </item>
    <item>
      <title>MySQL - InnoDB 스토리지 엔진 아키텍처</title>
      <link>https://loopstudy.tistory.com/457</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Real MySQL 8.0 (신판)&lt;/b&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4장 아키텍처 InnoDB 스토리지 엔진 아키텍처&lt;/b&gt;를 정리한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;자세한 내용이 궁금하면 책을 읽어보는 걸 권장한다.&lt;/p&gt;
&lt;figure id=&quot;og_1678886430592&quot; style=&quot;color: #000000; text-align: left;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;book&quot; data-og-title=&quot;Real MySQL 8.0 (1권) - YES24&quot; data-og-description=&quot;『Real MySQL 8.0』은 『Real MySQL』을 정제해서 꼭 필요한 내용으로 압축하고, MySQL 8.0의 GTID와 InnoDB 클러스터 기능들과 소프트웨어 업계 트렌드를 반영한 GIS 및 전문 검색 등의 확장 기능들을 추가로&quot; data-og-host=&quot;www.yes24.com&quot; data-og-source-url=&quot;http://www.yes24.com/Product/Goods/103415627&quot; data-og-url=&quot;http://www.yes24.com/Product/Goods/103415627&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/llnbR/hyRERa5cKV/gXf5jpa6rUE3HZVj2ifYG0/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200,https://scrap.kakaocdn.net/dn/fR5ur/hyRDSo9lPL/nA4YG1Yin7wq7RVBpD4Mh0/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200,https://scrap.kakaocdn.net/dn/H2SMM/hyREU6IpHV/HC6catr6vjTZ6S4DauVXak/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;http://www.yes24.com/Product/Goods/103415627&quot; data-source-url=&quot;http://www.yes24.com/Product/Goods/103415627&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;color: #000000; background-image: url('https://scrap.kakaocdn.net/dn/llnbR/hyRERa5cKV/gXf5jpa6rUE3HZVj2ifYG0/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200,https://scrap.kakaocdn.net/dn/fR5ur/hyRDSo9lPL/nA4YG1Yin7wq7RVBpD4Mh0/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200,https://scrap.kakaocdn.net/dn/H2SMM/hyREU6IpHV/HC6catr6vjTZ6S4DauVXak/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot; style=&quot;color: #000000;&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Real MySQL 8.0 (1권) - YES24&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;『Real MySQL 8.0』은 『Real MySQL』을 정제해서 꼭 필요한 내용으로 압축하고, MySQL 8.0의 GTID와 InnoDB 클러스터 기능들과 소프트웨어 업계 트렌드를 반영한 GIS 및 전문 검색 등의 확장 기능들을 추가로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;www.yes24.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;InnoDB&amp;nbsp;스토리지&amp;nbsp;엔진&amp;nbsp;아키텍처&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;InnoDB는 MySQL 스토리지 엔진 가운데 가장 많이 사용되며, 엔진 중에서 거의 유일하게 레코드 기반 잠금을 제공한다. 그 덕분에 높은 동시성 처리가 가능하고 안정적이며 성능이 뛰어나다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;1150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqJnRJ/btr33zesGLD/lLjRFk2QnN5C1PWSQPp9v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqJnRJ/btr33zesGLD/lLjRFk2QnN5C1PWSQPp9v0/img.png&quot; data-alt=&quot;InnoDB 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqJnRJ/btr33zesGLD/lLjRFk2QnN5C1PWSQPp9v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqJnRJ%2Fbtr33zesGLD%2FlLjRFk2QnN5C1PWSQPp9v0%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;1510&quot; height=&quot;1150&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;1150&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;InnoDB 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;프라이머리 키(PK)에 의한 클러스터링&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;InnoDB의 모든 테이블은 PK를 기준으로 클러스터링되어 저장된다. 이는 PK 값의 순서대로 디스크에 저장되며, 모든 세컨더리 인덱스는 레코드의 주소 대신 PK의 값을 논리적인 주소로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다른 스토리지 엔진인 MyISAM은 클러스터링 키를 지원하지 않으며, PK를 포함한 모든 인덱스는 물리적인 레코드의 주소 값(ROWID)을 가진다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;외래 키 지원&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InnoDB 에서 지원하기 때문에 MyISAM 혹은 MEMORY 테이블에서는 사용할 수 없다. 외래 키는 운영의 불편함(전파로 인한 데드락 발생) 때문에 서비스용 데이터베이스에서는 생성하지 않는 경우가 있는데, 개발 환경의 데이터베이스에서는 좋은 가이드 역할을 할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;외래 키가 생성되어 있을 경우 foreign_key_checks 변수를 OFF로 설정하면 외래 키 체크 작업을 멈출 수 있다.&lt;br /&gt;다만, 해당 변수 범위는 GLOBAL, SESSION 둘 다 사용되기 때문에 현재 세션에서만 멈추게 해야 한다.&lt;br /&gt;&lt;br /&gt;SET foreign_key_checks=OFF;&lt;br /&gt;SET SESSION&amp;nbsp;foreign_key_checks=OFF;&lt;br /&gt;&lt;br /&gt;만약에 SESSION을 명시하지 않으면, 자동적으로 현재 세션의 설정만 변경하도록 되어있기 때문에 위의 명령어 2가지는 같은 효과를 낸다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MVCC(Multi Version Concurrecy Control)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;MVCC는 레코드 레벨의 트랜잭션을 지원하는 DBMS가 제공하는 기능이며, 가장 큰 목적은 잠금을 사용하지 않는 일관된 읽기를 제공하는 데 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;MEMBER라는 테이블을 생성하고 id, name, area 값으로 12, 홍길동, 서울을 넣으면 데이터베이스 상태는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1186&quot; data-origin-height=&quot;824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkDsr0/btr38LqRWT6/uB9h9YiHVtdn4G5f5PeT40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkDsr0/btr38LqRWT6/uB9h9YiHVtdn4G5f5PeT40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkDsr0/btr38LqRWT6/uB9h9YiHVtdn4G5f5PeT40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkDsr0%2Fbtr38LqRWT6%2FuB9h9YiHVtdn4G5f5PeT40%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;1186&quot; height=&quot;824&quot; data-origin-width=&quot;1186&quot; data-origin-height=&quot;824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 레코드의 값을 UPDATE 진행하면 데이터베이스 상태는 다음과 처럼 변경된다.&lt;/p&gt;
&lt;pre id=&quot;code_1678891830541&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE member SET area='경기' WHERE id=12;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IgWnL/btr34LFIeaV/TunOp8DCs4KSzEh0U6bSW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IgWnL/btr34LFIeaV/TunOp8DCs4KSzEh0U6bSW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IgWnL/btr34LFIeaV/TunOp8DCs4KSzEh0U6bSW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIgWnL%2Fbtr34LFIeaV%2FTunOp8DCs4KSzEh0U6bSW0%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;1178&quot; height=&quot;880&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UPDATE가 실행되면 커밋 실행 여부에 상관없이 InnoDB의 버퍼풀은 입력된 '경기'로 업데이트되고, 이전 값은 언두 로그로 복사되어 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그럼 해당 레코드가 COMMIT, ROLLBACK 되지 않은 상태에서 다른 사용자가 해당 레코드를 조회하면 어디서 데이터가 조회될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 MySQL 시스템 변수에 설정된 격리 레벨에 따라 달라진다.&lt;/p&gt;
&lt;pre id=&quot;code_1678892852537&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 격리 레벨을 확인하는 방법
SELECT @@GLOBAL.transaction_isolation;
SELECT @@SESSION.transaction_isolation;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1678892897336&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 격리 레벨 변경하는 방법
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;격리 수준이 READ&amp;nbsp;UNCOMMITTED 경우에 다른 사용자는 InnoDB 버퍼풀에 존재하는 변경된 값인 '경기'를 조회하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지는 COMMIT이 되기 전의 값인 '서울'을 조회하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이렇게 MVCC는 하나의 레코드에 대해 2개의 버전이 유지되고, 필요에 따라 어느 데이터가 보이는지 여러 가지 상황에 달라지는 구조다. (만약 COMMIT이 되지 않고 변경되는 데이터가 많아지면 언두 로그에 보관되는 데이터는 점점 늘어나게 된다.)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;잠금 없는 일관된 읽기(Non-Locking Consistent Read)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;InnoDB 스토리지 엔진의 MVCC 덕분에 잠금 없이 읽기 작업이 가능하다. 격리 수준이 SERIALIZABLE이 아니라면 순수 읽기(SELECT) 작업은 다른 트랜잭션의 변경 작업에 관계없이 잠금을 대기하지 않고 바로 실행된다. 이를 '잠금 없는 일관된 읽기'라고 하며, InnoDB에서는 언두 로그를 사용한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자동 데드락 감지&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InnoDB는 내부적으로 잠금 교착 상태를 체크하는 잠금 대기 목록을 그래프(Wait-for List) 형태로 관리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 잠금 대기 상태를 볼 수 있는 쿼리다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679044090645&quot; class=&quot;mipsasm&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
    r.trx_id waiting_trx_id,
    r.trx_mysql_thread_id waiting_thread,
    r.trx_query waiting_query,
    b.trx_id blocking_trx_id,
    b.trx_mysql_thread_id blocking_thread,
    b.trx_query blocking_query
FROM 
    information_schema.innodb_lock_waits w
    INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
    INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKN4nX/btr4vJGpQ4f/pr1fgEl6akndJE6gQpA8Zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKN4nX/btr4vJGpQ4f/pr1fgEl6akndJE6gQpA8Zk/img.png&quot; data-alt=&quot;잠금 대기 상태 트랜잭션을 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKN4nX/btr4vJGpQ4f/pr1fgEl6akndJE6gQpA8Zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKN4nX%2Fbtr4vJGpQ4f%2Fpr1fgEl6akndJE6gQpA8Zk%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;990&quot; height=&quot;68&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;68&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;information_schema.innodb_trx를 따로 구분한 이유는 information_schema.innodb_lock_waits 에서 제공하는 대기 상태와 잠금 상태의 트랜잭션 id를 구분해서 사용하기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oJPEk/btr4ssTWxVT/2qaNsP2rEGSb8GMADoivF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oJPEk/btr4ssTWxVT/2qaNsP2rEGSb8GMADoivF0/img.png&quot; data-alt=&quot;information_schema.innodb_trx가 제공하는 정보&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oJPEk/btr4ssTWxVT/2qaNsP2rEGSb8GMADoivF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoJPEk%2Fbtr4ssTWxVT%2F2qaNsP2rEGSb8GMADoivF0%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;848&quot; height=&quot;98&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;98&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;information_schema.innodb_trx가 제공하는 정보&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 sys 스키마에서 제공하는 뷰를 이용하는 방법도 있다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679044621324&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  waiting_trx_id,
  waiting_pid,
  waiting_query,
  blocking_trx_id,
  blocking_pid,
  blocking_query
FROM sys.innodb_lock_waits;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InnoDB는 이를 활용해서 교착 상태에 빠진 트랜잭션 중에서 하나를 강제로 종료하는데,&amp;nbsp;트랜잭션마다 가진 언두 로그양이 적은 걸 기준으로 롤백한다. 언두 로그가 적다는 것은 부하가 적다는 의미다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다만 동시 처리 스레드가 많으면 데드락 감지 서비스가 느려지는데, 이는 데드락 감지 스레드가 목록 검사를 위해 잠금 테이블에 새로운 잠금을 걸기 때문이다. 이 경우 많은 CPU 자원을 소모할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 데드락 관련된 시스템 변수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- innodb_deadlock_defect : 데드락 감지를 제어한다. 기본 값 ON이면 감지하고 OFF 하면 멈춘다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- innodb_lock_wait_timeout : 기본 값 50초로 데드락 상황이 해당 시간을 넘기면 자동으로 요청 실패를 반환하게 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- innodb_print_all_deadlocks : 데드락이 발생할 InnoDB가 모든 데드락 정보를 로그로 출력할지 정하는 변수로 기본 값은 OFF다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자동화된 장애 복구&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InnoDB에는 여러 가지 장애 복구 기능이 존재하고 서버가 실행될 때 자동으로 수행한다. 만약에 복구할 수 없는 손상이 존재한다면 MySQL은 종료가 된다. 종료가 되면 손상된 파일에 따라 설정 파일의 innodb_force_recovery 시스템 변수를 설정해서 시작해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 로그 파일이 손상되면 6으로 설정하고 기동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 파일이 손상되면 1로 설정하고 기동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 알 수 없다면 1 ~ 6까지 차례대로 설정하고 기동 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;innodb_force_recovery의 값이 커질수록 복구 가능성은 낮아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자는 0 ~ 6까지 존재하며, 0을 제외한 숫자는 SELECT 구문을 제외하고 INSERT, UPDATE, DELETE를 사용할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 숫자의 의미다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 0 : 기본값으로 복구 방법이 아닌 일반적인 방법으로 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1(SRV_FORCE_IGNORE_CORRUPT) : 테이블 스페이스의 데이터나 인덱스 페이지의 오류를 무시하고 서버를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2(SRV_FORCE_NO_BACKGROUD) : 백그라운드 메인 스레드를 실행하지 않고 서버를 실행한다. 메인 스레드가 언두 데이터를 삭제하는 과정에 발생한 에러라면 이 모드를 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 3(SRV_FORCE_NO_TRX_UNDO) : 커밋되지 않고 종료된 트랜잭션을 그대로 유지하면서 서버를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 4(SRV_FORCE_NO_IBUF_MERGE) : InnoDB가 인서트 버퍼를 무시하고 강제로 서버를 실행한다. 인서트 버퍼는 실제 데이터가 아닌 인덱스 관련된 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 5(SRV_FORCE_NO_UNDO_LOG_SCAN) : 서버가 종료된 시점의 커밋 안된 작업도 모두 커밋처리해서 실행하므로 잘못된 데이터를 남긴다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 6(SRV_FORCE_NO_LOG_REDO) : 마지막 체크포인트 시점의 데이터로 실행한다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;InnoDB 버퍼풀 &lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;버퍼풀은 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해 두는 공간으로, I/O 작업을 줄여주는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버퍼 풀의 크기 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;버퍼 풀의 크기는 메모리 크기에 따라 운영체제와 각 클라이언트 스레드를 고려해서 설정이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 8GB 미만 : 50%만 버퍼풀로 설정하고 나머지는 운영체제 등에 사용하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 8GB 이상 : 50%로 시작해서 천천히 비율을 올리면서 최적점을 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 50GB 이상 : 대략 15~30GB를 제외하고 버퍼풀로 할당하면서 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 버퍼풀에 관련된 변수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- innodb_buffer_pool_size : 버퍼 풀의 크기를 지정한다. 기존보다 작하면 서비스에 영향도가 높다. 변경은 크리티컬 한 영향을 끼치기 때문에 한가할 때 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- innodb_buffer_pool_instances : 버퍼 풀 인스턴스 개수를 지정한다. 기본 값은 8이지만 메모리 크기가 1GB 미만이면 1개이고, 40GB 이면 8개 유지한다. 인스턴스당 5GB 설정이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- innodb_old_blocks_time : 기본값은 1000(초)이며, 버퍼 풀의 데이터가 이 시간을 넘어가면 제거된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외에도 여러 가지 변수가 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/poil7/btr4v87BCJI/wbZwstQYeEsCtXv1NJoCo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/poil7/btr4v87BCJI/wbZwstQYeEsCtXv1NJoCo1/img.png&quot; data-alt=&quot;innodb_buffer% 로 검색된 목록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/poil7/btr4v87BCJI/wbZwstQYeEsCtXv1NJoCo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpoil7%2Fbtr4v87BCJI%2FwbZwstQYeEsCtXv1NJoCo1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;374&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;innodb_buffer% 로 검색된 목록&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버퍼 풀의 구조&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;버퍼 풀은 메모리 공간을 페이지 크기(innodb_page_size 설정값)에 따라 쪼개어 데이터를 저장한다. 이 버퍼 풀을 3가지 자료 구조로 관리하는데 다음과 같다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- LRU(Least Recently Used) List : 한번 읽어 온 데이터를 최대한 유지해서 디스크 읽기를 최소화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Flush List : 디스크로 동기화되지 않은 더티 페이지의 변경 시점 기준으로 목록을 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Free List : 비어있는 목록으로 디스크의 페이지를 읽어올 경우 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버퍼 풀과 리두 로그&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;버퍼 풀은 서버의 성능 향상을 위해 데이터 캐시와 쓰기 버퍼링 두 가지 용도가 있는데,&amp;nbsp;버퍼 풀의 메모리 공간은 데이터 캐시 기능만 연관되어 있다. 쓰기 버퍼링 성능 향상을 이해하려면 버퍼 풀과 리두 로그 관계를 알아야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;706&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJhOvL/btr4wFdg06H/un8VjUb2vUcFPGNSMLwwp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJhOvL/btr4wFdg06H/un8VjUb2vUcFPGNSMLwwp0/img.png&quot; data-alt=&quot;상태 변경이 생기면 버퍼 풀에 유지하면서 리두 로그 파일에 기록된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJhOvL/btr4wFdg06H/un8VjUb2vUcFPGNSMLwwp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJhOvL%2Fbtr4wFdg06H%2Fun8VjUb2vUcFPGNSMLwwp0%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;916&quot; height=&quot;706&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;706&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;상태 변경이 생기면 버퍼 풀에 유지하면서 리두 로그 파일에 기록된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버퍼 풀에는 변경된 데이터 공간인 더티 페이지가 존재하는데 디스크 상태와 다르기 때문에 언젠가는 디스크로 기록되어야 할 데이터라 버퍼 풀에 계속 머무를 순 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;InnoDB에서 리두 로그는 고정 크기 파일을 순환 고리처럼 사용한다. 즉, 기존의 엔트리를 새로운 엔트리로 덮어 쓰인다. 순환되는 리두 로그를 구분하기 위해서 로그 포지션이 존재하는데, 매번 기록될 때마다 계속 증가된 값을 갖아서 LSN(Log Sequence Number)라고 한다. 그리고 InnoDB는 주기적인 체크포인트 이벤트로 리두 로그와 버퍼 풀의 더티 페이지를 디스크로 동기화한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;*언두(Undo) 로그와 리두(Redo) 로그의 차이점.&lt;br /&gt;언두 로그는 변경 전 데이터를 보관하는 장소로 롤백이 될 경우 이전 데이터로 복구한다.&lt;br /&gt;반대로 리두 로그는 데이터 변경 이력 을 로그 파일로 보관하고 문제가 생길 경우 해당 파일을 통해 데이터를 복구한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버퍼 풀 상태 백업 및 복구&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;InnoDB의 버퍼 풀은 쿼리 성능에 밀접되어 있다. 버퍼 풀의 데이터가 적재되어 있으면 디스크를 읽지 않아도 처리되는데, &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;서버를 재시작하면 처리 성능이 1/10도 안되는 걸 볼 수 있다. 버퍼 풀에 데이터가 적재되어 있는 걸 워밍업이라 한다. MySQL 5.6 버전부터는 버퍼 풀 덤프 및 적재 기능이 추가되었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679399548604&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 서버 다운전에 버퍼 풀 백업 여부
SHOW VARIABLES LIKE 'innodb_buffer_pool_dump_now';
-- 서버 시작 후 백업된 버퍼 풀 상태 복구 여부
SHOW VARIABLES LIKE 'innodb_buffer_pool_load_now';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외에 관련된 변수가 몇가지 더 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kz2aa/btr45kAMuJg/XKU1rIHkazp1fzE2QaAfek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kz2aa/btr45kAMuJg/XKU1rIHkazp1fzE2QaAfek/img.png&quot; data-alt=&quot;버퍼 풀 백업 변수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kz2aa/btr45kAMuJg/XKU1rIHkazp1fzE2QaAfek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkz2aa%2Fbtr45kAMuJg%2FXKU1rIHkazp1fzE2QaAfek%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;618&quot; height=&quot;110&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;버퍼 풀 백업 변수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7doEe/btr5aEFJ0ME/JnxhvRsAO2HmlpI7bp9PFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7doEe/btr5aEFJ0ME/JnxhvRsAO2HmlpI7bp9PFk/img.png&quot; data-alt=&quot;버퍼 풀 복구 변수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7doEe/btr5aEFJ0ME/JnxhvRsAO2HmlpI7bp9PFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7doEe%2Fbtr5aEFJ0ME%2FJnxhvRsAO2HmlpI7bp9PFk%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;620&quot; height=&quot;110&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;110&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버퍼 풀의 백업은 데이터 디렉터리에 ib_buffer_pool 파일로 생성되는데, 파일 크기는 버퍼 풀의 크기에 비해 상당히 작은데 메타 데이터의 정보만 가져와서 저장하기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;48&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lw8ba/btr5cEMm1mY/eMqEgDBXyc9pm8dkPSphRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lw8ba/btr5cEMm1mY/eMqEgDBXyc9pm8dkPSphRK/img.png&quot; data-alt=&quot;변수로 해당 파일명을 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lw8ba/btr5cEMm1mY/eMqEgDBXyc9pm8dkPSphRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLw8ba%2Fbtr5cEMm1mY%2FeMqEgDBXyc9pm8dkPSphRK%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;686&quot; height=&quot;48&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;48&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;만약 복구 중에 너무 오래걸려서 중단하고 서비스를 시작하려면 innodb_buffer_pool_load_abort 변수를 이용하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679399809888&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SET GLOBAL innodb_buffer_pool_load_abort = ON;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버퍼 풀의 적재 내용 확인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;MySQL 8.0 부터 추가된 innodb_cached_indexes 테이블을 통해 테이블의 인덱스별로 버퍼 풀의 적재상황을 볼 수 있게 되었다.&lt;/p&gt;
&lt;pre id=&quot;code_1679401138014&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
	it.name table_name,
	ii.name index_name,
    ici.n_cached_pages n_cached_pages
FROM information_schema.innodb_tables it
	INNER JOIN information_schema.innodb_indexes ii ON ii.table_id = it.table_id
	INNER JOIN information_schema.innodb_cached_indexes ici ON ici.index_id = ii.index_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Double Write Buffer&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리두 로그는 변경된 내용만 기록하는데 더티 페이지에서 디스크 파일로 플러시 될 때 하드웨어 오작동 등 문제가 생기면 일부분만 기록되는 문제가 생긴다. 데이터 무결성을 위해 Double Write(이중 쓰기)가 사용되는데, Double Write는 데이터를 디스크의 두 곳에 기록한다는 의미다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;962&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RVaUh/btr5fmKAetL/gOJ5TUkJEjb5GZ258gpi4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RVaUh/btr5fmKAetL/gOJ5TUkJEjb5GZ258gpi4k/img.png&quot; data-alt=&quot;Double Write 작동 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RVaUh/btr5fmKAetL/gOJ5TUkJEjb5GZ258gpi4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRVaUh%2Fbtr5fmKAetL%2FgOJ5TUkJEjb5GZ258gpi4k%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;1052&quot; height=&quot;962&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;962&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Double Write 작동 방식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Double Write Buffer는 InnoDB가 디스크에 데이터를 기록할 때 사용되는 버퍼로 데이터 페이지가 디스크에 기록되기전에 버퍼에 복사하는 곳이다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;*Double Write와 리두 로그 차이점.&lt;br /&gt;Double Write Buffer는 InnoDB가 데이터를 디스크에 기록하기 전에, 데이터 먼저 기록하는 곳으로 디스크에 데이터를 안전하게 기록하게 보호한다.&lt;br /&gt;리두 로그는 변경 사항(트랜잭션)을 로그에 기록하는 곳으로 문제가 생기면 해당 파일로 복구한다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;언두 로그&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 트랜잭션과 격리 수준을 보장하기 위해 DML(insert, update, delete)로 변경되기 이전 버전의 데이터를 별도로 백업하는 곳을 언두 로그라고 한다. 주로 2가지 용도로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 트랜잭션 보장&lt;/b&gt; : 트랜잭션이 롤백되면 언두 로그에 백업해둔 이전 데이터를 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 격리 수준 보장&lt;/b&gt; : 데이터 변경 중에도 다른 커넥션이 접근하면 트랜잭션 격리 수준에 맞게 언두 로그 데이터를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;언두 테이블스페이스(Undo Tablespace) 관리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언두 로그가 저장되는 공간을 언두 테이블스페이스라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;828&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xBov9/btr5eoPoCKx/qYA9f9EkO7ZFdq5ROcHvQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xBov9/btr5eoPoCKx/qYA9f9EkO7ZFdq5ROcHvQ1/img.png&quot; data-alt=&quot;언두 테이블스페이스 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xBov9/btr5eoPoCKx/qYA9f9EkO7ZFdq5ROcHvQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxBov9%2Fbtr5eoPoCKx%2FqYA9f9EkO7ZFdq5ROcHvQ1%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;808&quot; height=&quot;828&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;828&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;하나의 언두 테이블스페이스는 1개 ~ 128개의 롤백 세그먼트를 가지며, 롤백 세그먼트는 1개 이상의 언두 슬롯을 가진다. 언두 슬롯이 남는건 문제가 없지만 언두 슬롯이 부족해지면 트랜잭션을 시작할 수 없는 문제가 생긴다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 롤백 세그먼트는 InnoDB 페이지 크기를 16바이트로 나눈 값의 개수만큼 언두 슬롯을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 16KB 페이지라면 롤백 세그먼트는 1024개 언두슬롯을 가지며, 하나의 트랜잭션에 사용되는 언두 슬롯은 INSERT, UPDATE, DELETE에 따라 최대 4개의 언두 슬롯을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 트랜잭션이 대략 2개 정도의 언두 슬롯을 사용한다는 가정하에 트랜잭션의 개수는 아래 수식으로 예측할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 동시 트랜잭션 = (InnoDB 페이지 크기) / 16 * innodb_rollback_segments(롤백 세그먼트 개수) * innodb_undo_tablespaces(언두 테이블 스페이스 개수) / 하나의 트랜잭션이 사용할 언두 슬롯 개수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;131072 = &lt;/span&gt;16 * 1024 / 16 * 128 * 2 / 2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략 131072개 정도의 트랜잭션이 동시 처리된다.&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;체인지 버퍼(Change Buffer)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태가 변경되면 데이터 파일뿐만 아니라 인덱스 업데이트를 위해 디스크를 읽는 작업이 필요해서 자원소모가 크다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InnoDB는 버퍼 풀에 있다면 바로 업데이트를 수행하지만 디스크를 읽어야한다면 임시 저장 공간에 저장해두고 사용자에게 결과를 반환하는 형식으로 성능을 향상하는데 이 공간을 &lt;b&gt;체인지 버퍼&lt;/b&gt;라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;innodb_change_buffering 변수를 사용하면 INSERT, DELETE, UPDATE 작업별로 체인지 버퍼를 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- all : 모든 인덱스 관련 작업을 버퍼링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- none : 버퍼링 안함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- inserts : 인덱스에 새로운 아이템을 추가하는 작업만 버퍼링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- deletes : 인덱스에서 기존 아이템을 삭제하는 작업만 버퍼링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- changes : 인덱스에서 추가하고 삭제하는 작업만(inserts + deletes) 버퍼링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- purges : 인덱스 아이템을 영구적으로 삭제하는 작업만 버퍼링(백그라운드 작업)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKIVIo/btr5gvI6m2I/CSfsQD5X6L24zjw7ytKkek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKIVIo/btr5gvI6m2I/CSfsQD5X6L24zjw7ytKkek/img.png&quot; data-alt=&quot;기본 값은 all&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKIVIo/btr5gvI6m2I/CSfsQD5X6L24zjw7ytKkek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKIVIo%2Fbtr5gvI6m2I%2FCSfsQD5X6L24zjw7ytKkek%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;360&quot; height=&quot;52&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기본 값은 all&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;리두 로그 및 리두 버퍼&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리두 로그는 MySQL 서버가 비정상적인 종료를 했을 때 데이터를 잃지 않게 해주는 안전장치다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비정상적으로 종료되면 InnoDB 엔진은 두 가지 종류의 일관되지 않은 데이터를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1. 커밋됐지만 데이터 파일에 기록되지 않은 데이터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2. 롤백됐지만 데이터 파일에 이미 기록된 데이터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번의 경우 리두 로그를 다시 복사하면 끝난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번의 경우 언두 로그를 통해 복구하지만 리두 로그를 사용한다. 리두 로그 통해 변경, 롤백, 트랜잭션 실행 중간이였는지 판단한다.&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;innoDB는 리두 로그를 디스크에 기록하는 걸 제어하는 innodb_flush_log_at_trx_commit 변수를 제공하는데 다음과 같은 값을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;0&lt;/b&gt; : 1초에 한번씩 리두 로그를 디스크로 기록하고 동기화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;1&lt;/b&gt; : 매번 트랜잭션이 커밋될 때 마다 디스크로 기록하고 동기화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;2&lt;/b&gt; : 매번 트랜잭션이 커밋될 때 마다 디스크로 기록하지만 동기화는 1초마다 실행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;48&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/noe4F/btr5rbaVn6p/97eqmEWaTz8OUZ72PSaLNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/noe4F/btr5rbaVn6p/97eqmEWaTz8OUZ72PSaLNk/img.png&quot; data-alt=&quot; 기본 값은 1 이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/noe4F/btr5rbaVn6p/97eqmEWaTz8OUZ72PSaLNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnoe4F%2Fbtr5rbaVn6p%2F97eqmEWaTz8OUZ72PSaLNk%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;410&quot; height=&quot;48&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;48&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; 기본 값은 1 이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;리두 로그 아카이빙&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL 8.0부터 리두 로그 아카이빙 기능이 추가되었다. innodb_redo_log_archive_dirs 변수를 통해 저장할 디렉터리를 설정하는데 설정 방식은 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1679495120996&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SET GLOBAL innodb_redo_log_archive_dirs='label1:directory_path1[;label2:directory_path2;&amp;hellip;]';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;62&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y9xH1/btr5oBuW21C/NKfc6Tcag7Bj40SRTknisK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y9xH1/btr5oBuW21C/NKfc6Tcag7Bj40SRTknisK/img.png&quot; data-alt=&quot;기본 값은 없으며, 설정된 값이 없으면 아카이빙은 안된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y9xH1/btr5oBuW21C/NKfc6Tcag7Bj40SRTknisK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy9xH1%2Fbtr5oBuW21C%2FNKfc6Tcag7Bj40SRTknisK%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;520&quot; height=&quot;62&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;62&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정이 되면 UDF(사용자 정의 함수)를 통해 아카이빙을 실행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1679493583674&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DO innodb_redo_log_archive_start('backup', '20230322');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 첫번째 식별자는 디렉터리에 대한 레이블이고, 두번째 식별자는 서브디렉터리의 이름이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;만약에 권한이 없는 등 여러 에러가 발생하면&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1; text-align: start;&quot; href=&quot;https://dev.mysql.com/blog-archive/mysql-innodb-redo-log-archiving/&quot;&gt;가이드&lt;/a&gt;를 참고하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아카이빙 중지는 단순하게 innodb_redo_log_archive_stop을 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1679496858339&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DO innodb_redo_log_archive_stop();&lt;/code&gt;&lt;/pre&gt;
&lt;p 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;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;어댑티브 해시 인덱스&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어댑티브 해시 인덱스는 B-Tree 검색 시간을 줄여주는 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 읽히는 데이터 페이지의 키 값으로 해시값을 만들어서 레코드가 저장된 데이터 페이지를 즉시 찾아갈 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 인덱스는 '인덱스 키 값'과 키 값이 저장된 '데이터 페이지 주소'의 쌍으로 관리되는데, 인덱스 키 값은 'B-Tree 인덱스의 고유 번호(id)와 B-Tree 인덱스의 실제 키 값' 조합으로 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어댑티브 해시 인덱스를 이용해서 성능 향상을 볼 수 있는 경우는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 디스크의 데이터가 InnoDB 버퍼 풀 크기와 비슷한 경우(디스크 읽기가 적을 경우)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 동등 조건 검색(동등 비교와 IN 연산자)이 많은 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 쿼리가 데이터 중에서 일부 데이터에만 집중되는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 경우는 성능향상에 도움이 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 디스크 읽기가 많은 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특정 패턴의 쿼리가 많은 경우(조인이나 LIKE 패턴 검색)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 매우 큰 데이터를 가진 테이블의 레코드를 폭넓게 읽는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 테이블 삭제작업의 경우 해당 테이블의 데이터 페이지가 저장된 어댑티브 해시 테이블의 인덱스도 모두 삭제되는 등 자원 소모가 크다.&lt;/p&gt;</description>
      <category>서적/Real MySQL 8.0</category>
      <category>Double Write</category>
      <category>InnoDB</category>
      <category>MVCC</category>
      <category>MySQL</category>
      <category>Real MySQL 8.0</category>
      <category>redo log</category>
      <category>Undo Log</category>
      <category>버퍼 풀</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/457</guid>
      <comments>https://loopstudy.tistory.com/457#entry457comment</comments>
      <pubDate>Thu, 23 Mar 2023 00:13:02 +0900</pubDate>
    </item>
    <item>
      <title>MySQL - 엔진 아키텍처</title>
      <link>https://loopstudy.tistory.com/456</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Real MySQL 8.0 (신판)&lt;/b&gt;을 &lt;b&gt;4장 아키텍처 일부분&lt;/b&gt;을 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 내용이 궁금하면 책을 읽어보는 걸 권장한다.&lt;/p&gt;
&lt;figure id=&quot;og_1676531005909&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;book&quot; data-og-title=&quot;Real MySQL 8.0 (1권) - YES24&quot; data-og-description=&quot;『Real MySQL 8.0』은 『Real MySQL』을 정제해서 꼭 필요한 내용으로 압축하고, MySQL 8.0의 GTID와 InnoDB 클러스터 기능들과 소프트웨어 업계 트렌드를 반영한 GIS 및 전문 검색 등의 확장 기능들을 추가로&quot; data-og-host=&quot;www.yes24.com&quot; data-og-source-url=&quot;http://www.yes24.com/Product/Goods/103415627&quot; data-og-url=&quot;http://www.yes24.com/Product/Goods/103415627&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/llnbR/hyRERa5cKV/gXf5jpa6rUE3HZVj2ifYG0/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200,https://scrap.kakaocdn.net/dn/fR5ur/hyRDSo9lPL/nA4YG1Yin7wq7RVBpD4Mh0/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200,https://scrap.kakaocdn.net/dn/H2SMM/hyREU6IpHV/HC6catr6vjTZ6S4DauVXak/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200&quot;&gt;&lt;a href=&quot;http://www.yes24.com/Product/Goods/103415627&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://www.yes24.com/Product/Goods/103415627&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/llnbR/hyRERa5cKV/gXf5jpa6rUE3HZVj2ifYG0/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200,https://scrap.kakaocdn.net/dn/fR5ur/hyRDSo9lPL/nA4YG1Yin7wq7RVBpD4Mh0/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200,https://scrap.kakaocdn.net/dn/H2SMM/hyREU6IpHV/HC6catr6vjTZ6S4DauVXak/img.jpg?width=965&amp;amp;height=1200&amp;amp;face=0_0_965_1200');&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;Real MySQL 8.0 (1권) - YES24&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;『Real MySQL 8.0』은 『Real MySQL』을 정제해서 꼭 필요한 내용으로 압축하고, MySQL 8.0의 GTID와 InnoDB 클러스터 기능들과 소프트웨어 업계 트렌드를 반영한 GIS 및 전문 검색 등의 확장 기능들을 추가로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.yes24.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MySQL 전체 아키텍처&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL 서버는 크게 MySQL 엔진과 스토리지 엔진 2가지로 구분되며, 이 둘을 합쳐 MySQL 서버라 부른다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;1182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTM58d/btr2PR8H8vA/yikyQK20KuXkXBsd5KGVzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTM58d/btr2PR8H8vA/yikyQK20KuXkXBsd5KGVzK/img.png&quot; data-alt=&quot;MySQL 서버의 전체 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTM58d/btr2PR8H8vA/yikyQK20KuXkXBsd5KGVzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTM58d%2Fbtr2PR8H8vA%2FyikyQK20KuXkXBsd5KGVzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1488&quot; height=&quot;1182&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;1182&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MySQL 서버의 전체 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MySQL 엔진 -&amp;nbsp;&lt;/b&gt;클라이언트의 접속 및 쿼리 요청을 처리하는 커넥션 핸들러와 SQL 파서 및 전처리기, 옵티마이저가 중심을 이룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스토리지 엔진 -&lt;/b&gt;&amp;nbsp;요청된 SQL 문장을 분석 및 최적화하며, 데이터를 저장하거나 읽어오는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핸들러 API - &lt;/b&gt;MySQL 엔진의&amp;nbsp;쿼리 실행기에서 데이터를 읽거나 쓰기를 할 때 스토리지 엔진에 요청하는 걸 핸들러(Handler) 요청이라 하고, 사용되는 API가 핸들러 API다. 핸들러 API가 얼마나 작업되었는지는 아래의 구문을 통해 결과를 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1678362433198&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW GLOBAL STATUS LIKE 'Handler%'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QWDRb/btr2ZVB5DQ7/10j47mw86DkmhnoNM1Oo20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QWDRb/btr2ZVB5DQ7/10j47mw86DkmhnoNM1Oo20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QWDRb/btr2ZVB5DQ7/10j47mw86DkmhnoNM1Oo20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQWDRb%2Fbtr2ZVB5DQ7%2F10j47mw86DkmhnoNM1Oo20%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;356&quot; height=&quot;620&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MySQL 스레딩 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL 서버는 스레드 기반으로 작동하며 포그라운드(Foreground) 스레드와 백그라운드(Background) 스레드로 구분된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;1006&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rzxx9/btr22NDe68i/rbKdKv6Se04JfxPXVfXkE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rzxx9/btr22NDe68i/rbKdKv6Se04JfxPXVfXkE1/img.png&quot; data-alt=&quot;MySQL의 스레딩 모델&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rzxx9/btr22NDe68i/rbKdKv6Se04JfxPXVfXkE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRzxx9%2Fbtr22NDe68i%2FrbKdKv6Se04JfxPXVfXkE1%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;1362&quot; height=&quot;1006&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;1006&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MySQL의 스레딩 모델&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 구문을 이용하여 실행 중인 스레드 목록을 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1678362612460&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT thread_id, name, type, processlist_user, processlist_host
FROM performance_schema.threads 
ORDER BY type, thread_id&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;888&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YkGXP/btr20ALeXZs/KGtcgxhbvKjzHjQ169qwK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YkGXP/btr20ALeXZs/KGtcgxhbvKjzHjQ169qwK1/img.png&quot; data-alt=&quot;실행중인 스레드 목록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YkGXP/btr20ALeXZs/KGtcgxhbvKjzHjQ169qwK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYkGXP%2Fbtr20ALeXZs%2FKGtcgxhbvKjzHjQ169qwK1%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;1284&quot; height=&quot;888&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;888&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;type을 보면 백그라운드와 포그라운드로 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막에 보이는 &lt;b&gt;thread/sql/one_connection&lt;/b&gt;이 실제 사용자의 요청을 처리하는 스레드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복되는 이름은 MySQL 서버 설정에 의해 병렬로 처리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;포그라운드 스레드(클라이언트 스레드)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;포그라운드 스레드는 MySQL에 접속한 클라이언트만큼 존재하며, 클라이언트 사용자가 요청하는 쿼리 문장을 처리한다. 사용자가 작업을 마치고 종료하면, 해당 사용자를 담당하는 스레드는 스레드 캐시(Thread cache)로 돌아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;※ 포그라운드 스레드와 사용자 스레드는 같은 의미로 사용한다.&lt;/b&gt;&lt;/span&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;&amp;nbsp;포그라운드 스레드는 데이터 버퍼 &amp;amp; 캐시로부터 데이터를 갖고 온다. 버퍼 &amp;amp; 캐시에도 없다면 직접 디스크의 데이터나 인덱스 파일로부터 읽어와 처리한다. 여기서 스토리지 엔진에 따라 작동하는 방식이 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MyISAM -&lt;/b&gt;&amp;nbsp;디스크 쓰기까지 포그라운드 스레드가 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;InnoDB -&lt;/b&gt;&amp;nbsp;데이터 버퍼 &amp;amp; 캐시까지만 포그라운드 스레드가 처리하고, 디스크 쓰기는 백그라운드 스레드가 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;백그라운드 스레드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스토리지 엔진에 따라 백그라운드 스레드로 작업하는게 달라지며, 그중 InnoDB는 아래의 작업이 백그라운드 스레드로 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 인서트 버퍼(Insert Buffer)를 병합하는 스레드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 로그를 디스크로 기록하는 스레드 (Log thread)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- InnoDB를 버퍼 풀의 데이터를 디스크에 기록하는 스레드 (Write thread)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 데이터를 버퍼로 읽어 오는 스레드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 잠금이나 데드락을 모니터링하는 스레드&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; 메모리 할당 및 사용 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL의 메모리 공간은 스레드가 공유하는 여부에 따라 글로벌 메모리 영역과 로컬(세션) 메모리 영역 2가지로 구분되고 다음과 같은 특징을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;글로벌 메모리 영역 -&lt;/b&gt; 클라이언트 스레드의 수와 무관하게 하나의 메모리 공간만 할당되며, 필요에 따라 2개 이상 할당받기도 한다. 생성된 글로벌 메모리 영역은 모든 스레드에 공유된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;로컬 메모리 영역 -&lt;/b&gt;&amp;nbsp;각 클라이언트 스레드별로 독립적으로 할당되기 때문에 서로가 공유되지 않는다. 또한, 쿼리의 용도별로 필요에 따라 공간이 할당될 수도 안될 수 있다. ex) 소트 버퍼, 조인 버퍼는 쿼리를 실행한 순간에만 할당되고 다시 해제한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVetqt/btr2X9AQ9FL/8Ky2WCpsCCRyGtPm3HYGXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVetqt/btr2X9AQ9FL/8Ky2WCpsCCRyGtPm3HYGXK/img.png&quot; data-alt=&quot;MySQL의 메모리 영역&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVetqt/btr2X9AQ9FL/8Ky2WCpsCCRyGtPm3HYGXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVetqt%2Fbtr2X9AQ9FL%2F8Ky2WCpsCCRyGtPm3HYGXK%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;1406&quot; height=&quot;836&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MySQL의 메모리 영역&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;플러그인 스토리지 엔진 모델&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL은 독특하게 플러그인 모델을 사용하며, 기본적으로 제공하는 스토리지 엔진 이외의 다양한 기능을 가진 스토리지 엔진이 존재한다. 필요에 따라 개발자가 직접 스토리지 엔진도 개발해서 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;694&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BlUgH/btr2RhlWk1h/JcrPYS3tfGxPp9Z1ZGsi3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BlUgH/btr2RhlWk1h/JcrPYS3tfGxPp9Z1ZGsi3K/img.png&quot; data-alt=&quot;MySQL 플러그인 모델&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BlUgH/btr2RhlWk1h/JcrPYS3tfGxPp9Z1ZGsi3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBlUgH%2Fbtr2RhlWk1h%2FJcrPYS3tfGxPp9Z1ZGsi3K%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;1160&quot; height=&quot;694&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;694&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MySQL 플러그인 모델&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;쿼리가 실행되는 과정은 보면 대부분의 작업은 MySQL 엔진에서 처리되고, 마지막에 '데이터 읽기/쓰기' 작업만 스토리지 엔진에 의해 처리된다. 이는 사용자가 스토리지 엔진을 만든다 해도 DBMS 전체 기능이 아닌 일부분만 수행하는 엔진을 작성한다는 의미다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zgYFt/btr2UokP0k7/eme0Stkcbr9jcFXcqKQtnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zgYFt/btr2UokP0k7/eme0Stkcbr9jcFXcqKQtnk/img.png&quot; data-alt=&quot;스토리지 엔진은 데이터 읽기/쓰기 작업만 처리한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zgYFt/btr2UokP0k7/eme0Stkcbr9jcFXcqKQtnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzgYFt%2Fbtr2UokP0k7%2Feme0Stkcbr9jcFXcqKQtnk%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;1260&quot; height=&quot;630&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;630&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;스토리지 엔진이 여러개가 존재하는데 MySQL 엔진은 핸들러(Handler)를 통해 스토리지 엔진에게 데이터를 가져오고 저장하도록 명령한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;&lt;b&gt;※ 프로그래밍 언어에서는 어떤 기능을 호출하기 위해 사용하는 운전대와 같은 역할을 하는 객체를 핸들러라고 표현한다.&lt;/b&gt;&lt;/i&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;다음 구문을 통해 스토리지 엔진 목록을 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1678367434761&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW ENGINES&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LPSnV/btr2UnlW6Sn/1hKDZbMbDdAZV7AEWQhmg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LPSnV/btr2UnlW6Sn/1hKDZbMbDdAZV7AEWQhmg1/img.png&quot; data-alt=&quot;스토리지 엔진 목록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LPSnV/btr2UnlW6Sn/1hKDZbMbDdAZV7AEWQhmg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLPSnV%2Fbtr2UnlW6Sn%2F1hKDZbMbDdAZV7AEWQhmg1%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;1284&quot; height=&quot;342&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;342&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;Support 컬럼의 값은 4가지로 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;YES -&lt;/b&gt;&amp;nbsp;MySQL 서버에 해당 스토리지 엔진이 포함되어 있고, 활성화된 상태.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DEFAULT -&lt;/b&gt;&amp;nbsp;YES와 동일하지만, 필수 스토리지 엔진을 뜻함. (없으면 MySQL 실행 안됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NO -&lt;/b&gt;&amp;nbsp;현재 MySQL 서버에 포함되지 않았음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DISABLED -&lt;/b&gt;&amp;nbsp;MySQL 서버에 포함되었지만, 활성화되지 않음.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;컴포넌트&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;MySQL 플러그인은 몇 가지 단점이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 플러그인은 오직 MySQL 서버와 인터페이스 할 수 있고, 플러그인끼리는 통신할 수 없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 플러그인은 MySQL 서버의 변수나 함수를 직접 호출해서 위험함(캡슐화 안됨)&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;MySQL 8.0 부터는 이러한 단점을 보완하는 컴포넌트 아키텍처를 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 &lt;a href=&quot;https://www.tutorialspoint.com/mysql/mysql_install_component_statement.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;가이드&lt;/a&gt;에서 제공하는 컴포넌트를 설치하는 방법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1678368771258&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- Syntax
INSTALL COMPONENT component_name [, component_name ] ...

-- exmaple
INSTALL COMPONENT 'file://component_log_sink_syseventlog';
Query OK, 0 rows affected (0.36 sec)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;쿼리 실행 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;사용자가 요청한 SQL 요청은 아래와 같이 실행되며, 기능별로 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;808&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zjlid/btr21DA2blv/TUiYYkERFTtOhEryquPe40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zjlid/btr21DA2blv/TUiYYkERFTtOhEryquPe40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zjlid/btr21DA2blv/TUiYYkERFTtOhEryquPe40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZjlid%2Fbtr21DA2blv%2FTUiYYkERFTtOhEryquPe40%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;1628&quot; height=&quot;808&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;808&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&amp;nbsp;쿼리 파서&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 요청한 SQL를 서버가 이해할 수 있는 토큰으로 분리한다. 기본적인 문법 오류는 여기서 발견되어 사용자에게 오류 메시지를 보낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&amp;nbsp;전처리기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리 문장에 구조적인 문제점 여부를 확인한다. 각 토큰을 테이블 이름, 칼럼, 또는 내장 함수 등에 매핑해 해당 객체의 존재 여부와 접근 권한 등의 확인 과정이 여기에 속한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;b&gt;옵티마이저&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리 문장을 저렴한 비용으로 빠르게 처리하는 역할을 담당하며, DBMS의 두뇌에 해당된다. 실행 계획(Exception Plan)을 수립한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;b&gt;실행 엔진&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 단계에서 만들어진 실행 계획대로 핸들러에게 요청해서 결과를 받고, 또 다른 핸들러 요청의 입력으로 연결하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&amp;nbsp;핸들러(스토리지 엔진)&lt;/b&gt;&lt;/p&gt;
&lt;p 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;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;쿼리 캐시 (8.0 부터 제거됨)&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;쿼리 캐시는 SQL의 실행 결과를 메모리에 캐시 하고, 동일 SQL 쿼리가 실행되면 테이블을 읽지 않고 즉시 결과를 반환하기 때문에 빠른 성능을 보였다. 하지만 테이블 데이터가 변경되면 관련된 캐시도 모두 삭제하는 심각한 성능 저하를 유발하고 다양한 버그의 원인으로 지목되었는데, MySQL 8.0이 되면서 완전히 제거가 되었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스레드 풀&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;스레드 풀은 MySQL 서버 엔터프라이즈 에디션에 내장되어 있고, MySQL 커뮤니티에는 지원하지 않는다.&amp;nbsp;대신 플러그인 형태로 제공되는 Percona server의 스레드 풀을 알아본다.&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;스레드 풀은 MySQL 서버의 CPU가 제한된 개수의 스레드 처리에만 집중할 수 있게 서버의 자원 소모를 줄이는 것이 목적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Percona Server의 스레드 풀은 기본적으로 CPU 코어의 개수만큼 스레드 그룹을 생성하는데, thread_pool_size 변수로 조정할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/thread-pool-tuning.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식 문서&lt;/a&gt;에 따르면&lt;br /&gt;- InnoDB 경우, 최적의 thread_pool_size 설정 값은 16 ~ 36 사이일 가능성이 가장 높으며, 가장 일반적인 최적 값은 24 ~ 36이다.&amp;nbsp;&lt;br /&gt;&amp;nbsp;DBT2 및 Sysbench와 같은 워크로드의 경우, InnoDB 최적화 값은 보통 36 정도이며, 쓰기에 집중적인 워크로드의 경우 더 낮아질 수 있다.&lt;br /&gt;- MyISAM 경우,&amp;nbsp;thread_pool_size 설정값은 상당히 낮아야한다. 최적의 성능은 4 ~ 8로 보인다. 높은 값을 설정하면 성능에 부정적인 영향을 미치지만, 심각한 영향을 끼치진 않는다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;스레드 그룹의 모든 스레드가 작업 중이라면 새로운 스레드 그룹을 추가할지, 기다릴 지 여부를 판단해야 하는데 스레드풀의 타이머 스레드가 주기적으로 스레드 그룹의 상태를 체크한다. thread_pool_stall_limit 변수의 밀리초만큼 작업이 안 끝난다면 새로운 스레드를 추가해서 작업을 하는데, 전체 스레드의 개수는 thread_pool_max_threads 변수의 값을 넘어설 순 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉, 모든 스레드가 작업중인 상태에서 새로운 요청은&amp;nbsp;thread_pool_stall_limit 밀리초만큼 대기해야 한다. 이때 서비스의 민감도에 따라 대기시간을 낮추게 설정해도 된다. 다만 0으로 설정하면 스레드를 사용하지 않는 것이 좋을 것이다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;트랜잭션 지원 메타데이터&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;DB 서버에서 '테이블의 구조 정보와 스토어드 프로그램 등의 정보'를 데이터 딕셔너리 혹은 메타데이터라 부른다. MySQL 5.7 버전까지는 파일로 관리하다가 MySQL가 비정상 종료를 하게 되면 파일 정보가 일관되지 않아서 문제가 생겼는데, 이를 'DB나 테이블이 깨졌다'라고 표현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;MySQL 8.0부터는 테이블 구조 정보와 스토어드 프로그램 등의 정보를 모두 InnoDB의 테이블에 저장하도록 개선되었다. mysql DB는 통째로 mysql.ibd라는 테이블 스페이스에 저장하게 된다.&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;span style=&quot;background-color: #fcfcfc; color: #333333; text-align: left;&quot;&gt;&amp;nbsp;InnoDB에서 데이터 딕셔너리가 테이블에 저장된다고 했는데, 실제 mysql DB 테이블 목록을 살펴보면 해당 테이블이 보이지 않는다. 이는 사용자가 임의로 수정하지 못하게 보여주지 않을뿐이지 실제로는 테이블이 존재한다. 대신 MySQL 서버는 뷰를 통해 조회할 수 있게 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678885945070&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: left;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW CREATE TABLE INFORMATION_SCHEMA.TABLES; 

/*
CREATE TEMPORARY TABLE `TABLESsys_config` (
  `TABLE_CATALOG` varchar(512) NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) NOT NULL DEFAULT '',
  `TABLE_TYPE` varchar(64) NOT NULL DEFAULT '',
  `ENGINE` varchar(64) DEFAULT NULL,
  `VERSION` bigint(21) unsigned DEFAULT NULL,
  `ROW_FORMAT` varchar(10) DEFAULT NULL,
  `TABLE_ROWS` bigint(21) unsigned DEFAULT NULL,
  `AVG_ROW_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `DATA_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `MAX_DATA_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `INDEX_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `DATA_FREE` bigint(21) unsigned DEFAULT NULL,
  `AUTO_INCREMENT` bigint(21) unsigned DEFAULT NULL,
  `CREATE_TIME` datetime DEFAULT NULL,
  `UPDATE_TIME` datetime DEFAULT NULL,
  `CHECK_TIME` datetime DEFAULT NULL,
  `TABLE_COLLATION` varchar(32) DEFAULT NULL,
  `CHECKSUM` bigint(21) unsigned DEFAULT NULL,
  `CREATE_OPTIONS` varchar(255) DEFAULT NULL,
  `TABLE_COMMENT` varchar(2048) NOT NULL DEFAULT ''
) ENGINE=MEMORY DEFAULT CHARSET=utf8
*/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;조회해보면 데이터 딕셔너리(메타 데이터)를 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1678885997258&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM INFORMATION_SCHEMA.TABLES;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3394&quot; data-origin-height=&quot;1800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ9Kwn/btr34Uh2hJ2/AOIqjVhcLeGLJIudCmVUY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ9Kwn/btr34Uh2hJ2/AOIqjVhcLeGLJIudCmVUY0/img.png&quot; data-alt=&quot;테이블에 저장된 데이터 딕셔너리 목록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ9Kwn/btr34Uh2hJ2/AOIqjVhcLeGLJIudCmVUY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ9Kwn%2Fbtr34Uh2hJ2%2FAOIqjVhcLeGLJIudCmVUY0%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;3394&quot; height=&quot;1800&quot; data-origin-width=&quot;3394&quot; data-origin-height=&quot;1800&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;&amp;nbsp;하지만 InnoDB가 아닌 MyISAM, CSV 스토리지 엔진의 메타 정보는 여전히 저장 공간이 필요하는데, SDI(Serialized Dictionary Information) 파일을 사용한다.&lt;/p&gt;</description>
      <category>서적/Real MySQL 8.0</category>
      <category>MySQL</category>
      <category>MySQL 8.0</category>
      <category>Real MySQL 8.0</category>
      <category>엔진 아키텍처</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/456</guid>
      <comments>https://loopstudy.tistory.com/456#entry456comment</comments>
      <pubDate>Wed, 15 Mar 2023 22:18:19 +0900</pubDate>
    </item>
    <item>
      <title>DDD 세레나데 2주차 - 크게 소리 내어 모델링하기</title>
      <link>https://loopstudy.tistory.com/449</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;NEXTSTEP에서 진행하는 교육과정&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;DDD 세레나데 2기&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1667464286976&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;DDD(Domain-Driven Design) 세레나데&quot; data-og-description=&quot;&quot; data-og-host=&quot;edu.nextstep.camp&quot; data-og-source-url=&quot;https://edu.nextstep.camp/s/W08ac6g9&quot; data-og-url=&quot;https://edu.nextstep.camp/c/GwN2MSqv&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/vF0Yc/hyQpu9OGW0/EQT4E0nnusZfYYmKL4GkKk/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565,https://scrap.kakaocdn.net/dn/MCcc9/hyQn3MNszr/kjKzN1R2GHf7URKFVKoopK/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565&quot;&gt;&lt;a href=&quot;https://edu.nextstep.camp/s/W08ac6g9&quot; data-source-url=&quot;https://edu.nextstep.camp/s/W08ac6g9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/vF0Yc/hyQpu9OGW0/EQT4E0nnusZfYYmKL4GkKk/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565,https://scrap.kakaocdn.net/dn/MCcc9/hyQn3MNszr/kjKzN1R2GHf7URKFVKoopK/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565');&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;DDD(Domain-Driven Design) 세레나데&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;edu.nextstep.camp&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교육을 수강한 지 1년이 지났지만, 이제야 후기를 작성한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2주차 후기&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHRdyQ/btrQljaKBTi/lR8fKZmHvgmkKXS00hnbhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHRdyQ/btrQljaKBTi/lR8fKZmHvgmkKXS00hnbhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHRdyQ/btrQljaKBTi/lR8fKZmHvgmkKXS00hnbhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHRdyQ%2FbtrQljaKBTi%2FlR8fKZmHvgmkKXS00hnbhk%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;331&quot; height=&quot;440&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2주차는 모델링을 주제로&amp;nbsp;&lt;b&gt;&lt;a href=&quot;https://loopstudy.tistory.com/334?category=1052663&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;유비쿼터스 언어&lt;/a&gt;, &lt;a href=&quot;https://loopstudy.tistory.com/339&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;바운디드 컨텍스트&lt;/a&gt;, &lt;a href=&quot;https://loopstudy.tistory.com/450?category=1052663&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이벤트 스토밍&lt;/a&gt;&lt;/b&gt;을 배우는데 간단하게 설명하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어는 구성원이 사용하는 비즈니스 용어를 하나로 통일한 언어이며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 도메인 범위를 정한다고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 스토밍은 비즈니스 도메인을 빠르게 탐색하고 학습하여 유비쿼터스 언어와 바운디드 컨텍스트를 정하는 데 큰 도움을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 배운 내용은 DDD를 적용하는 회사가 아니더라도 적용할 수 있는 좋은 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 스토밍으로 구성원간 서로 다른 관점을 해소시키고 통일시키는 과정은 앞으로 협업에 많은 도움을 주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 결과물을 토대로 신규입사자에게 빠른 적응을 도울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼭 장점만은 있는 것은 아니다. 같은 용어라도 바운디드 컨텍스트에 따라 의미가 달라질 수 있기 때문에, 컨텍스트에 따라 용어의 의미를 구분해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;1단계 - 용어 사전 만들기&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1667484511082&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;1단계 - 용어 사전 만들기 by loop-study &amp;middot; Pull Request #68 &amp;middot; next-step/ddd-strategic-design&quot; data-og-description=&quot;안녕하세요 리뷰어님 이번 미션을 진행하게 된 박현철입니다. 유비쿼터스 언어를 정리해봤는데 개발자와 기획자, 사용자 모두에게 공통으로 사용될 수 있도록 했는지 잘 모르겠습니다.   피&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/ddd-strategic-design/pull/68&quot; data-og-url=&quot;https://github.com/next-step/ddd-strategic-design/pull/68&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dkAtSp/hyQqNQyJfi/YLYWMHsui1JohLE3kyKBq1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/next-step/ddd-strategic-design/pull/68&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/ddd-strategic-design/pull/68&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dkAtSp/hyQqNQyJfi/YLYWMHsui1JohLE3kyKBq1/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;1단계 - 용어 사전 만들기 by loop-study &amp;middot; Pull Request #68 &amp;middot; next-step/ddd-strategic-design&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님 이번 미션을 진행하게 된 박현철입니다. 유비쿼터스 언어를 정리해봤는데 개발자와 기획자, 사용자 모두에게 공통으로 사용될 수 있도록 했는지 잘 모르겠습니다.   피&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;README.md에 작성한다.&lt;/li&gt;
&lt;li&gt;한글명과 영문명, 간단한 설명을 표로 정리한다.&lt;/li&gt;
&lt;li&gt;미션을 진행함에 있어 아래 문서를 적극 활용한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dooray.com/htmls/guides/markdown_ko_KR.html&quot;&gt;마크다운(Markdown) - Dooray!&lt;/a&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1156&quot; data-origin-height=&quot;656&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G90Si/btrRa3d6ncm/aciAsmNkI8ziBdDThuAE50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G90Si/btrRa3d6ncm/aciAsmNkI8ziBdDThuAE50/img.png&quot; data-alt=&quot;코드로 파악한 요구 사항.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G90Si/btrRa3d6ncm/aciAsmNkI8ziBdDThuAE50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG90Si%2FbtrRa3d6ncm%2FaciAsmNkI8ziBdDThuAE50%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;689&quot; height=&quot;391&quot; data-origin-width=&quot;1156&quot; data-origin-height=&quot;656&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드로 파악한 요구 사항.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난주에 작성한 요구사항으로 진행하는 미션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요구사항의 단어를 통해 어떤 의미를 갖는지 용어 사전(유비쿼터스 언어)을 작성하는데, 개발자의 관점으로 프로젝트 내부에 용어 사전을 작성한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 현업이라면 비개발자도 볼 수 있는 곳에서 용어 사전을 작성하고 관리한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qRdNk/btrRc8ZODch/61kNWkX9TgoLF6d130Nkp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qRdNk/btrRc8ZODch/61kNWkX9TgoLF6d130Nkp0/img.png&quot; data-alt=&quot;개발자의 시점으로 작성된 용어사전&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qRdNk/btrRc8ZODch/61kNWkX9TgoLF6d130Nkp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqRdNk%2FbtrRc8ZODch%2F61kNWkX9TgoLF6d130Nkp0%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;2004&quot; height=&quot;578&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;578&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;2주차 1단계는 진행속도가 빠르다, 요구사항으로 기반으로 용어 사전을 작성하기 때문이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;용어 사전(유비쿼터스 언어)을 정의함으로써 얻는 장점 중 하나가 별도의 모델링 도구를 사용하지 않고 정의된 용어들을 코드에 그대로 녹일 수 있다.&lt;br /&gt;현재 용어사전에서 코드에 작성하기 적절하지 않거나 어색한 영문명이 있으면 확인해보는 것도 중요하다. &amp;nbsp;- 리뷰어&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;2단계 - 모델링&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1668405986527&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;2단계 - 모델링  by loop-study &amp;middot; Pull Request #73 &amp;middot; next-step/ddd-strategic-design&quot; data-og-description=&quot;안녕하세요 박현철입니다. 모델링이란 용어에 ERD 다이어그램을 생각했지만 힌트를 보니 생각했던거와 전혀달라서 원하는 방향으로 진행했는지 가물가물합니다. 확인 부탁드리겠습니다. 감사&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/ddd-strategic-design/pull/73&quot; data-og-url=&quot;https://github.com/next-step/ddd-strategic-design/pull/73&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rGRSL/hyQzbpc6K7/kUzTIu3QvfK67Fd4eTSa51/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/next-step/ddd-strategic-design/pull/73&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/ddd-strategic-design/pull/73&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rGRSL/hyQzbpc6K7/kUzTIu3QvfK67Fd4eTSa51/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;2단계 - 모델링 by loop-study &amp;middot; Pull Request #73 &amp;middot; next-step/ddd-strategic-design&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 박현철입니다. 모델링이란 용어에 ERD 다이어그램을 생각했지만 힌트를 보니 생각했던거와 전혀달라서 원하는 방향으로 진행했는지 가물가물합니다. 확인 부탁드리겠습니다. 감사&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;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;span&gt;&amp;nbsp;&lt;/span&gt;README.md에 모델링을 한다.&lt;/li&gt;
&lt;li&gt;설계한 것을 소리 내어 읽어 보고 말이 되는지 확인해 보는 것이 중요하다.&lt;/li&gt;
&lt;li&gt;미션을 진행함에 있어 아래 문서를 적극 활용한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dooray.com/htmls/guides/markdown_ko_KR.html&quot;&gt;마크다운(Markdown) - Dooray!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델링을 진행하는 단계다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SI/SM 시절, 모델링하면 개발자의 관점에서 데이터베이스 중심으로 ERD를 먼저 생각했었다. 이건 유비쿼터스 언어가 아닌 오로지 개발자만의 관점으로 작성된 모델로 비개발자는 이해하지 못했고, 비개발자한테 개발자의 관점으로 설명하는 문제가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 모델링이란 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기획자와 개발자 모두가 동일한 개념, 동일한 언어로 이야기하고, 애플리케이션이 무엇을 수행하는지 표현되는 모든 것이 모델링으로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;수첩에 끄적인 낙서, 한 줄로 적은 문장, 그림&lt;/i&gt;&lt;/b&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;이전 단계에서 작성한 md 파일에 이어서 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용어 사전처럼 한글명과 영문명을 둘 다 표기했다.&lt;/p&gt;
&lt;pre id=&quot;code_1668411757192&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;### 주문(`Order`)
- 주문(`Order`)은 주문 정보를 가진다.
  - 고객이 선택한 주문 유형(`OrderType`)을 가진다.
  - 고객이 확인할 수 있는 주문 상태(`OrderStatus`)를 가진다. 
  - 고객이 주문한 주문 메뉴(`OrderLineItem`)를 가진다. 
  - 주문이 들어온 주문 시각(orderDateTime)을 가진다.
  - 주문이 배송(`DELIVERY`)일 경우 경우 배송 받을 주소(deliveryAddress)를 가진다..  
  - 주문이 매장내 식사(`EAT_IN`)일 경우 주문이 들어온 주문 테이블(`OrderTable`)을 가진다.
  - 주문이 매장내 식사(`EAT_IN`)일 경우 주문 테이블(`OrderTable`)을 찾기 위한 주문 테이블 아이디(orderTableId)을 가진다.  
  
- 주문 유형(`OrderType`)은 주문 유형 정보를 가진다.
  - 배달 주문(`DELIVERY`)을 표현한다.
  - 포장 주문(`TAKEOUT`)을 표현한다.
  - 매장내 식사(`EAT_IN`)를 표현한다.

- 주문 상태(`OrderStatus`)는 주문 상태 정보를 가진다. 
  - 주문 대기(`WAITING`)를 표현한다.
  - 주문 접수(`ACCEPTED`)를 표현한다.
  - 주문 전달(`SERVED`)를 표현한다. 
  - 주문 배송 중(`DELIVERING`)를 표현한다. 
  - 주문 배송 완료(`DELIVERED`)를 표현한다.
  - 주문 완료(`COMPLETED`)를 표현한다. 

- 주문 메뉴(`OrderLineItem`)은 주문 메뉴 정보를 가진다.
  - 주문 받은 메뉴(`Menu`)를 가진다.
  - 주문 수량(Quantity)를 가진다.
  - 주문 금액(Price)를 가진다.
  
... (생략) ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;1312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EJ0dn/btrRcNhHbQe/kM54Lm3vYp2gf6LdTjEhDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EJ0dn/btrRcNhHbQe/kM54Lm3vYp2gf6LdTjEhDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EJ0dn/btrRcNhHbQe/kM54Lm3vYp2gf6LdTjEhDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEJ0dn%2FbtrRcNhHbQe%2FkM54Lm3vYp2gf6LdTjEhDk%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;1294&quot; height=&quot;1312&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;1312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 주문을 기준으로 진행된 최종 결과물 일부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 결과물이 되기까지 많은 어려움을 느꼈는데 가장 큰 문제는&amp;nbsp;무의식적으로 개발자의 관점으로 작성하게 된다는 점이다.&amp;nbsp;아래는 주문 모델링 초안이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HSH1u/btrQ6IIEzmy/iPmnN4xd724anrVhoAkXbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HSH1u/btrQ6IIEzmy/iPmnN4xd724anrVhoAkXbk/img.png&quot; data-alt=&quot;초안은 매욱 빈약했다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HSH1u/btrQ6IIEzmy/iPmnN4xd724anrVhoAkXbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHSH1u%2FbtrQ6IIEzmy%2FiPmnN4xd724anrVhoAkXbk%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;1248&quot; height=&quot;244&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;244&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;개발자 중심적이고, 상세적이지 않아서 비개발자는 이해할 수 없는 표현력이다.&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;46&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvYW4Q/btrQ5kOTgTC/nzC1TYge4ubcZmkoC37mV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvYW4Q/btrQ5kOTgTC/nzC1TYge4ubcZmkoC37mV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvYW4Q/btrQ5kOTgTC/nzC1TYge4ubcZmkoC37mV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvYW4Q%2FbtrQ5kOTgTC%2FnzC1TYge4ubcZmkoC37mV1%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;580&quot; height=&quot;46&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;46&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbqzbO/btrQ9bqldNv/403zdr084B9bMDqkcy8Nek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbqzbO/btrQ9bqldNv/403zdr084B9bMDqkcy8Nek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbqzbO/btrQ9bqldNv/403zdr084B9bMDqkcy8Nek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbqzbO%2FbtrQ9bqldNv%2F403zdr084B9bMDqkcy8Nek%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;856&quot; height=&quot;110&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cquVq9/btrRa3lilMD/9DDcBVXWS0SNdKO3WKyk90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cquVq9/btrRa3lilMD/9DDcBVXWS0SNdKO3WKyk90/img.png&quot; data-alt=&quot;리뷰어의 피드백을 많이 받았다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cquVq9/btrRa3lilMD/9DDcBVXWS0SNdKO3WKyk90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcquVq9%2FbtrRa3lilMD%2F9DDcBVXWS0SNdKO3WKyk90%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;976&quot; height=&quot;144&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;리뷰어의 피드백을 많이 받았다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;* 2단계가 끝나고 나서 다른 수강생은 어떤 표현을 했는데 한번 참고해보는 게 좋다.&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;3단계 - 기능 우선 패키지 구성하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1668422657263&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;[3단계 - 기능 우선 패키지 구성하기] by loop-study &amp;middot; Pull Request #84 &amp;middot; next-step/ddd-strategic-design&quot; data-og-description=&quot;안녕하세요 박현철입니다. 계층형 우선 패키지 구조에서 BOUNDED CONTEXT 중심의 패키지 구조로 변경했습니다. 진행하면서 메뉴, 메뉴그룹, 상품, 주문테이블, 주문이 서로 연관되어 동작하는게 많&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/ddd-strategic-design/pull/84&quot; data-og-url=&quot;https://github.com/next-step/ddd-strategic-design/pull/84&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/3dEFE/hyQzhDiLtm/zdnuPYKSC5EAo8z8bO2Adk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/next-step/ddd-strategic-design/pull/84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/ddd-strategic-design/pull/84&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/3dEFE/hyQzhDiLtm/zdnuPYKSC5EAo8z8bO2Adk/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;[3단계 - 기능 우선 패키지 구성하기] by loop-study &amp;middot; Pull Request #84 &amp;middot; next-step/ddd-strategic-design&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 박현철입니다. 계층형 우선 패키지 구조에서 BOUNDED CONTEXT 중심의 패키지 구조로 변경했습니다. 진행하면서 메뉴, 메뉴그룹, 상품, 주문테이블, 주문이 서로 연관되어 동작하는게 많&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;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;계층 우선 패키지 구조를 BOUNDED CONTEXT 중심의 패키지 구조로 리팩터링한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2주차 마지막 단계로 레이어 구조의 패키지를&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전까지 작업한 내용을 기반으로 바운디드 컨텍스트 중심의 패키지 구조로 변경하는 작업을 진행한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EMRz2/btrRaDN1Qmy/JjOXBskkLAU0LzxR0U1xz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EMRz2/btrRaDN1Qmy/JjOXBskkLAU0LzxR0U1xz1/img.png&quot; data-alt=&quot;이전에 작업한 모델링 기준으로 패키지를 분리한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EMRz2/btrRaDN1Qmy/JjOXBskkLAU0LzxR0U1xz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEMRz2%2FbtrRaDN1Qmy%2FJjOXBskkLAU0LzxR0U1xz1%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;433&quot; height=&quot;312&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;652&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;간단하게 생각하면 위의 모델링을 기준으로 분리만 하는 거다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mWdLT/btrRbZDgXfD/YwTdwh70cGrETJKRLRMGz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mWdLT/btrRbZDgXfD/YwTdwh70cGrETJKRLRMGz0/img.png&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;1442&quot; data-is-animation=&quot;false&quot; width=&quot;428&quot; height=&quot;1229&quot; data-widthpercent=&quot;46.13&quot; style=&quot;width: 45.590304488760026%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mWdLT/btrRbZDgXfD/YwTdwh70cGrETJKRLRMGz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmWdLT%2FbtrRbZDgXfD%2FYwTdwh70cGrETJKRLRMGz0%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;502&quot; height=&quot;1442&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4FFFC/btrRa1VJ3xv/vMZjHNKn0BfWMbNRF0hTF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4FFFC/btrRa1VJ3xv/vMZjHNKn0BfWMbNRF0hTF0/img.png&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;1274&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;53.87&quot; style=&quot;width: 53.246904813565564%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4FFFC/btrRa1VJ3xv/vMZjHNKn0BfWMbNRF0hTF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4FFFC%2FbtrRa1VJ3xv%2FvMZjHNKn0BfWMbNRF0hTF0%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;518&quot; height=&quot;1274&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;패키지 구조 변경 전과 후&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막상 분리를 진행하면서 도메인마다 서로 의존하는 게 많다 보니 여러 가지 행태가 떠 올랐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;[메뉴, 메뉴그룹] [상품] [주문테이블, 주문]&lt;/b&gt; 3가지로 패키지 구조를 나눠도 되지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;[메뉴, 메뉴그룹, 상품] [주문테이블, 주문]&lt;/b&gt;&amp;nbsp;2가지로 패키지 구조를 나눠도 되지 않을까?&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;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;진행하면서 메뉴, 메뉴그룹, 상품, 주문테이블, 주문이 서로 연관되어 동작하는게 많다보니&lt;br /&gt;[메뉴, 메뉴그룹] [상품] [주문테이블, 주문] 3가지로 나눠도 될거 같고,&lt;br /&gt;[메뉴, 메뉴그룹, 상품] [주문테이블, 주문] 크게 2가지로 나눠도 될거 같아 보이네요.&lt;br /&gt;그 외에도 생각하는 방식에 더 나눠지는 거 같아 생각할 수록 꼬여서 교육에서 진행된 요구사항과 모델링에서 정해진 컨텍스트를 기반으로 변경했습니다.&amp;nbsp; &lt;br /&gt;그리고&amp;nbsp;PurgomalumClient는 특정 컨텍스트에 속하지 않고 다양한 곳에서 공용으로 사용되어 infra에 그대로 두었는데 옳은 생각이지 궁금합니다.&lt;br /&gt;확인 부탁드립니다. &lt;br /&gt;감사합니다!&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 답변을 받았다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;좋은 고민 하고 계시네요 ㅎㅎ&lt;br /&gt;요구사항과 모델링 관점에서는 글로 표현하다 보니 이상한 부분을 많이 못 느끼셨을 수도 있을 것 같아요.&lt;br /&gt;그림으로 표현하고 각 컨텍스트간의 연관 관계를 나타내는 컨텍스트 맵을 그려보는 것을 권장드려요.&lt;br /&gt;요구사항과 모델링은 프로젝트가 진행됨에 따라서 지속적으로 변경되고 관리를 해줘야 합니다&amp;nbsp;&lt;br /&gt; &lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답변대로 요구사항과 모델링 과정에서 이상한 것을 전혀 느끼지 못하고,&amp;nbsp;패키지 구조를 분리하면서 의존관계를 눈으로 확인하면서 의문이 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 피드백으로 팁을 주셔서 가져왔다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Menu, MenuGroup, Product, OrderTable, Order를 각 바운디드 컨텍스트라 정의하고 패키지를 구성 잘해주셨습니다.&lt;br /&gt;Root Aggregate 기준으로 바운디드 컨텍스트를 나누어 주셨는데 저도 선호하는 방법이에요.&lt;br /&gt;제가 패키지를 나누는 방법도 공유해드릴게요.&lt;br /&gt;
&lt;pre id=&quot;code_1668434634087&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;* domain : domain layer 
    - aggreagte, repository, domain service 와 같이 도메인에서 처리하는 클래스들을 위치 시키는 편입니다.
* application : application laeyr 
    - 응용 서비스(application service)를 모아두곤 합니다. 
* api : presentation layer 
    - controller, adaptor와 같이 외부 client의 요청을 받는 클래스를 모아둡니다. 
* infra : infrastructure layer 
    - 이메일, 메시지 알림등과 같은 외부 서비스와 관련된 클래스를 모아둡니다.
* dto
    - request, response, layer 간 데이터 이동을 위한 클래스를 정의합니다.&lt;/code&gt;&lt;/pre&gt;
위 방법이 정답은 아니니 필요에 맞고 의미가 적절하게 패키지를 구성하면 된다고 생각해요.&lt;br /&gt;&lt;br /&gt;https://github.com/cheese10yun/spring-guide/blob/master/docs/directory-guide.md&lt;br /&gt;https://en.wikipedia.org/wiki/Package_principles&lt;br /&gt;https://medium.com/@ssowonny/package-by-feature-in-clean-architecture-projects-e14d25e3905e&lt;br /&gt;http://www.javapractices.com/topic/TopicAction.do?Id=205&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 나아가 패키지간 의존성 관리 방법에 대한 고민이 생기기도 하는데&amp;nbsp;토스 컨퍼런스 SLASH 22 발표 영상을 참고하면 좋다.&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=RVO02Z1dLF8&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/b6dS5P/hyQA10q8uh/SS1D6vebFt6zklkZHTk6RK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=746_212_980_466&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/RVO02Z1dLF8&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;</description>
      <category>교육 및 인강/DDD 세레나데</category>
      <category>DDD</category>
      <category>DDD 세레나데</category>
      <category>Domain-Driven Design</category>
      <category>nextstep</category>
      <category>도메인 주도 설계</category>
      <category>바운디드 컨텍스트</category>
      <category>유비쿼터스 언어</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/449</guid>
      <comments>https://loopstudy.tistory.com/449#entry449comment</comments>
      <pubDate>Mon, 14 Nov 2022 23:14:03 +0900</pubDate>
    </item>
    <item>
      <title>이벤트 스토밍(Event Storming)</title>
      <link>https://loopstudy.tistory.com/450</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;시작하면서&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구성원이 수긍하는 유비쿼터스 언어나 바운디드 컨텍스트를 정하려면 어떻게 해야 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스에 참여하는 구성원이 모여서 소통하고 정해야 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 책상에 앉아 회의처럼 이야기해야 할까? 그럼 전체적으로 정하는데 많은 시간이 소비되고 피로도가 쌓일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 방식으로 해야할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알베르토 브란돌리니(Alberto Brandolini)가 제안한 비즈니스 도메인을 빠르게 탐색하고 학습할 수 있는 이벤트 스토밍에 대해 알아보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이벤트 스토밍이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 전문가와 개발자를 학습 과정에 참여시키기 위한 빠른 설계 기술이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스와 데이터베이스가 아닌 비즈니스 및 비즈니스 프로세스에 중점을 둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 사람이 동일한 수준으로 접근할 수 있게 시각적인 접근 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;진행 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 벽이나 화이트보드에 포스트잇을 붙여 나간다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포스트잇마다 비즈니스 프로세스를 단계별로 적는다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 스토밍의 가치는 포스트잇이 아닌 커뮤니케이션이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구성원을 통해 부족한 비즈니스를 채울 수 있다.&lt;/li&gt;
&lt;li&gt;서로 다른 비즈니스를 하나로 통일할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보기 편하게 큰 글씨로 작성하고, 펜은 번지지 않는 것으로 쓴다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image.png&quot; data-origin-width=&quot;1105&quot; data-origin-height=&quot;547&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RV9xs/btrQpIv3IoX/h4DHDi0WW4hUuK7zdFIuqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RV9xs/btrQpIv3IoX/h4DHDi0WW4hUuK7zdFIuqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RV9xs/btrQpIv3IoX/h4DHDi0WW4hUuK7zdFIuqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRV9xs%2FbtrQpIv3IoX%2Fh4DHDi0WW4hUuK7zdFIuqk%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;1105&quot; height=&quot;547&quot; data-filename=&quot;image.png&quot; data-origin-width=&quot;1105&quot; data-origin-height=&quot;547&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image.jpeg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp15lQ/btrQrtD5Oc4/ODQ1xoXkaH2LbFH9NUXNaK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp15lQ/btrQrtD5Oc4/ODQ1xoXkaH2LbFH9NUXNaK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp15lQ/btrQrtD5Oc4/ODQ1xoXkaH2LbFH9NUXNaK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp15lQ%2FbtrQrtD5Oc4%2FODQ1xoXkaH2LbFH9NUXNaK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1282&quot; data-filename=&quot;image.jpeg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;도메인 이벤트(DOMAIN EVENT)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 전문가가 관심을 가지고 있는 어떤 사건으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트가 발생했다는 것은 상태가 변경되었다는 것을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 '~할 때', '~가 발생하면', '만약 ~하면'과 같은 요구사항은 상태 변경인 경우가 많고, 이런 요구사항은 이벤트로 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;COMMAND&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이벤트가 발생하는 원인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;AGGREGATE&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 오너십&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 독립적인 라이프사이클&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 독립적인 확장성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 보통 AGGREAGATE를 기준으로 BOUNDED CONTEXT를 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 혼자보다 다 같이 하는 것이 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 구현 코드보다 포스트잇을 변경하는 게 훨씬 저렴하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 커뮤니케이션을 통해 비즈니스 프로세스 자체를 잘 이해하고 개선한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 팀이 비즈니스(도메인)와 코드로 표현되는 모델의 차이를 이해하고 수정하도록 돕는 것이 중요하다.&lt;/p&gt;
&lt;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;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이벤트 스토밍 참여자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;사용자&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 불특정 다수의 소프트웨어 사용자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 애플리케이션에 대한 요구사항을 갖고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;도메인 전문가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 프로젝트에서 자신의 활동 범위가 개발이 아닌 애플리케이션 도메인인 구성원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 단순히 불특정 다수의 사용자가 아니라 주제에 대한 깊은 지식을 갖추고 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 도메인을 이해하는데 부자연스럽고 부정확한 용어 및 구조에 반대 의사를 표명해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;개발자&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 프로젝트에서 자신의 활동 범위가 개발인 구성원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시스템을 서술적이고 기능적인 용어로 이해하고 토론할지는 모르지만 전문가들의 언어에 담긴 의미는 알지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 개발자는 설계를 어렵게 만드는 모호함과 불일치를 찾아내는 데 촉각을 곤두세워야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자산화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진행된 이벤트 스토밍을 자료로 남긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;온라인으로 진행할 경우&amp;nbsp;&lt;a href=&quot;https://miro.com/&quot;&gt;Miro&lt;/a&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;blob&quot; data-origin-width=&quot;2154&quot; data-origin-height=&quot;1696&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byQvBW/btrQp4ZHA7e/knarjSWWBsAKzhPfIaaTb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byQvBW/btrQp4ZHA7e/knarjSWWBsAKzhPfIaaTb0/img.png&quot; data-alt=&quot;DDD 세레나데 2주차에 참여한 이벤트 스토밍 일부분&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byQvBW/btrQp4ZHA7e/knarjSWWBsAKzhPfIaaTb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyQvBW%2FbtrQp4ZHA7e%2FknarjSWWBsAKzhPfIaaTb0%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;2154&quot; height=&quot;1696&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2154&quot; data-origin-height=&quot;1696&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DDD 세레나데 2주차에 참여한 이벤트 스토밍 일부분&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;참고 자료&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;figure id=&quot;og_1667564396116&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;DDD(Domain-Driven Design) 세레나데&quot; data-og-description=&quot;&quot; data-og-host=&quot;edu.nextstep.camp&quot; data-og-source-url=&quot;https://edu.nextstep.camp/c/GwN2MSqv&quot; data-og-url=&quot;https://edu.nextstep.camp/c/GwN2MSqv&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rE3P8/hyQsfyN6KB/UclR3Fdchc1gwbCA2bQUkk/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565,https://scrap.kakaocdn.net/dn/w1Mnz/hyQr6Wbsgz/4pgf9wfRUdy90fFuBznmi1/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565&quot;&gt;&lt;a href=&quot;https://edu.nextstep.camp/c/GwN2MSqv&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://edu.nextstep.camp/c/GwN2MSqv&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rE3P8/hyQsfyN6KB/UclR3Fdchc1gwbCA2bQUkk/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565,https://scrap.kakaocdn.net/dn/w1Mnz/hyQr6Wbsgz/4pgf9wfRUdy90fFuBznmi1/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565');&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;DDD(Domain-Driven Design) 세레나데&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;edu.nextstep.camp&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>개발 &amp;amp; 방법론/DDD</category>
      <category>DDD 세레나데</category>
      <category>Domain-Driven Design</category>
      <category>Event Storming</category>
      <category>도메인 주도 설계</category>
      <category>이벤트 스토밍</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/450</guid>
      <comments>https://loopstudy.tistory.com/450#entry450comment</comments>
      <pubDate>Fri, 4 Nov 2022 20:59:13 +0900</pubDate>
    </item>
    <item>
      <title>DDD 세레나데 1주차 - 도메인 주도 설계 이해</title>
      <link>https://loopstudy.tistory.com/447</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;NEXTSTEP에서 진행하는 교육과정&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;DDD 세레나데 2기&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1667203292442&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;DDD(Domain-Driven Design) 세레나데&quot; data-og-description=&quot;&quot; data-og-host=&quot;edu.nextstep.camp&quot; data-og-source-url=&quot;https://edu.nextstep.camp/s/W08ac6g9&quot; data-og-url=&quot;https://edu.nextstep.camp/c/GwN2MSqv&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/vF0Yc/hyQpu9OGW0/EQT4E0nnusZfYYmKL4GkKk/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565,https://scrap.kakaocdn.net/dn/MCcc9/hyQn3MNszr/kjKzN1R2GHf7URKFVKoopK/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565&quot;&gt;&lt;a href=&quot;https://edu.nextstep.camp/s/W08ac6g9&quot; data-source-url=&quot;https://edu.nextstep.camp/s/W08ac6g9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/vF0Yc/hyQpu9OGW0/EQT4E0nnusZfYYmKL4GkKk/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565,https://scrap.kakaocdn.net/dn/MCcc9/hyQn3MNszr/kjKzN1R2GHf7URKFVKoopK/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565');&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;DDD(Domain-Driven Design) 세레나데&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;edu.nextstep.camp&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교육을 수강한 지 1년이 지났지만, 이제야 후기를 작성한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;b&gt;1주차 후기&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QoQ5n/btrP19mYLQF/T2tYRXVGFncrmMptjGTreK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QoQ5n/btrP19mYLQF/T2tYRXVGFncrmMptjGTreK/img.png&quot; data-alt=&quot;1주차 과정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QoQ5n/btrP19mYLQF/T2tYRXVGFncrmMptjGTreK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQoQ5n%2FbtrP19mYLQF%2FT2tYRXVGFncrmMptjGTreK%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;370&quot; height=&quot;569&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;772&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1주차 과정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1주차는 레거시 코드를 통해 도메인 주도 설계 등장 배경을 겪어보고, 왜 도메인 주도 설계인가를 알아본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리팩토링을 하기 위한 첫걸음으로 테스트 코드를 학습한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 코드를 작성하는 방법은 여러 가지로 모두 경험해보고 어느 상황에 사용하면 좋을지 알아본다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;텐트를 세우기 위해 말뚝이 필요하듯이 리팩터링을 하기 위해선 테스트 코드가 필요하다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 TDD, 클린코드 with Java 11기가 끝난 지 얼마 안 된 시점이라 생소한 개념이 많아서 따라가기 힘들었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 개념을 들어봤거나 사용해본 사람이라면 무난하게 진행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;SpringBootTest&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 애플리케이션 전체를 테스트하는 통합 테스트로 신뢰성이 가장 높다. 대신 속도가 느리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;WebMvcTest&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 전체가 아닌 Web Layer(Controller)만 테스트한다. 서비스 로직 결과는 스텁빙한다.&lt;/p&gt;
&lt;pre id=&quot;code_1667485600873&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@WebMvcTest(MenuGroupRestController.class)
class MenuGroupRestControllerTest extends MockMvcSupport {

    @Autowired
    private MockMvc webMvc;

    @MockBean
    private MenuGroupService menuGroupService;

    @BeforeEach
    void setUp() {
        fixtureMenuGroups();

        this.webMvc = ofUtf8MockMvc();
    }

    @DisplayName(&quot;메뉴그룹 생성하기&quot;)
    @Test
    void createMenuGroup() throws Exception {
        // given
        MenuGroup menuGroup = menuGroups.get(0);

        given(menuGroupService.create(any())).willReturn(menuGroup);

        // when
        ResultActions perform = webMvc.perform(
                post(&quot;/api/menu-groups&quot;)
                .content(&quot;{\&quot;name\&quot;:\&quot;추천메뉴\&quot;}&quot;)
                .contentType(&quot;application/json&quot;)
        );

        // then
        perform
                .andDo(print())
                .andExpect(status().is2xxSuccessful())
                .andExpect(jsonPath(&quot;$.id&quot;).isNotEmpty())
                .andExpect(jsonPath(&quot;$.name&quot;).value(menuGroup.getName()));
    }
    
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Mockito&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mockito를 이용한 Mock 테스트다.&lt;/p&gt;
&lt;pre id=&quot;code_1667485600874&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ExtendWith(MockitoExtension.class)
public class MenuServiceTest extends FixtureData {

    @Mock
    private MenuRepository menuRepository;

    @Mock
    private MenuGroupRepository menuGroupRepository;

    @Mock
    private ProductRepository productRepository;

    @Mock
    private PurgomalumClient purgomalumClient;

    @InjectMocks
    private MenuService menuService;
    
    ...
    
    @DisplayName(&quot;메뉴 생성&quot;)
    @Test
    void createMenu() {
        // given
        Menu menu = menus.get(0);

        given(menuGroupRepository.findById(menu.getMenuGroupId())).willReturn(Optional.of(menu.getMenuGroup()));
        given(productRepository.findAllById(any())).willReturn(Arrays.asList(menu.getMenuProducts().get(0).getProduct()));
        given(productRepository.findById(any())).willReturn(Optional.of(products.get(0)));
        given(menuRepository.save(any())).willReturn(menu);

        // when
        Menu createMenu = menuService.create(menu);

        // then
        assertThat(createMenu).isNotNull();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 대상의 외부 의존성을 Mock객체로 진행하는 테스트로 스텁빙을 통해 하나의 연극처럼 테스트를 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Fake 객체&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;독특했던 경험인 Fake 객체 테스트 방법으로&amp;nbsp;객체를 상속받아 진짜처럼 작동하게 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mockito을 대체할 수 있지만, 작성하고 관리하는데 손이 많이간다.&lt;/p&gt;
&lt;pre id=&quot;code_1667485600875&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class FakeMenuGroupRepository implements MenuGroupRepository {
    private final Map&amp;lt;UUID, MenuGroup&amp;gt; menuGroups = new HashMap&amp;lt;&amp;gt;();

    @Override
    public MenuGroup save(MenuGroup menuGroup) {
        menuGroups.put(menuGroup.getId(), menuGroup);
        return menuGroup;
    }

    @Override
    public Optional&amp;lt;MenuGroup&amp;gt; findById(UUID uuid) {
        return Optional.ofNullable(menuGroups.get(uuid));
    }

    @Override
    public List&amp;lt;MenuGroup&amp;gt; findAll() {
        return new ArrayList&amp;lt;&amp;gt;(menuGroups.values());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1667485600876&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MenuGroupRepositoryTest {
    // Fake 객체
    private FakeMenuGroupRepository menuGroupRepository = new FakeMenuGroupRepository();

    protected static final UUID FIRST_ID = UUID.randomUUID();
    protected static final UUID SECOND_ID = UUID.randomUUID();

    private MenuGroup createMenuGroup(UUID id, String menuGroupName) {
        MenuGroup menuGroup = new MenuGroup();
        menuGroup.setId(id);
        menuGroup.setName(menuGroupName);
        return menuGroup;
    }

    @DisplayName(&quot;메뉴그룹 저장&quot;)
    @Test
    void save() {
        MenuGroup menuGroup = createMenuGroup(FIRST_ID, &quot;일식&quot;);

        MenuGroup saveMenuGroup = menuGroupRepository.save(menuGroup);

        assertThat(menuGroup.getId()).isEqualTo(saveMenuGroup.getId());
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 테스트를 통한 코드 보호로 리팩토링 준비가 끝났다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1단계 - 문자열 덧셈 계산기&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1667211220052&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;Step1 - 문자열 덧셈 계산기  by loop-study &amp;middot; Pull Request #116 &amp;middot; next-step/ddd-legacy&quot; data-og-description=&quot;안녕하세요 박현철입니다. 제공해주는 테스트 코드 기반으로 진행했습니다. 커밋 내역은 여기서 확인 부탁드리겠습니다. 컨벤션을 준수했는지 체크 부탁드립니다. 감사합니다!&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/ddd-legacy/pull/116&quot; data-og-url=&quot;https://github.com/next-step/ddd-legacy/pull/116&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QcZCP/hyQpDy6RB5/NtkqUxCrrNjh79ijcuXwC1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/next-step/ddd-legacy/pull/116&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/ddd-legacy/pull/116&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QcZCP/hyQpDy6RB5/NtkqUxCrrNjh79ijcuXwC1/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;Step1 - 문자열 덧셈 계산기 by loop-study &amp;middot; Pull Request #116 &amp;middot; next-step/ddd-legacy&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 박현철입니다. 제공해주는 테스트 코드 기반으로 진행했습니다. 커밋 내역은 여기서 확인 부탁드리겠습니다. 컨벤션을 준수했는지 체크 부탁드립니다. 감사합니다!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;요구 사항&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환 (예: &amp;ldquo;&amp;rdquo; =&amp;gt; 0, &quot;1,2&quot; =&amp;gt; 3, &quot;1,2,3&quot; =&amp;gt; 6, &amp;ldquo;1,2:3&amp;rdquo; =&amp;gt; 6)&lt;/li&gt;
&lt;li&gt;앞의 기본 구분자(쉼표, 콜론) 외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 &amp;ldquo;//&amp;rdquo;와 &amp;ldquo;\n&amp;rdquo; 사이에 위치하는 문자를 커스텀 구분자로 사용한다. 예를 들어 &amp;ldquo;//;\n1;2;3&amp;rdquo;과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.&lt;/li&gt;
&lt;li&gt;문자열 계산기에 숫자 이외의 값 또는 음수를 전달하는 경우&lt;span&gt;&amp;nbsp;&lt;/span&gt;RuntimeException&lt;span&gt;&amp;nbsp;&lt;/span&gt;예외를 throw 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1주차 1단계는 JUnit5 테스트 코드에 익숙해지는 미션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 미션인데,&amp;nbsp;테스트 코드에만 몰입하다가&amp;nbsp;&lt;span&gt;계산기 역할을 분리하지 않고 하나로 뭉치는 실수와&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제공된 코드를 세심히 확인하지 않고 그대로 사용했더니 매번 비싼 비용을 치르는 문제가 있었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제대로 인지하지 못했고&amp;nbsp;리뷰어의 지적에 뒤늦게 수정했다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2단계 - 요구사항 정리&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1667222710850&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;2단계 - 요구사항 정리 by loop-study &amp;middot; Pull Request #138 &amp;middot; next-step/ddd-legacy&quot; data-og-description=&quot;안녕하세요 박현철입니다. 2단계 요구사항을 제출합니다. 지금까지 요구사항을 받아서 개발을 했지만 제공해주는 코드와 .http 기반으로 역으로 요구사항을 파악해보는건 처음이네요. 그리고 진&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/ddd-legacy/pull/138&quot; data-og-url=&quot;https://github.com/next-step/ddd-legacy/pull/138&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gIscN/hyQpFcSXn7/guySGYdnZQxe0IK66nac6K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/next-step/ddd-legacy/pull/138&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/ddd-legacy/pull/138&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gIscN/hyQpFcSXn7/guySGYdnZQxe0IK66nac6K/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;2단계 - 요구사항 정리 by loop-study &amp;middot; Pull Request #138 &amp;middot; next-step/ddd-legacy&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 박현철입니다. 2단계 요구사항을 제출합니다. 지금까지 요구사항을 받아서 개발을 했지만 제공해주는 코드와 .http 기반으로 역으로 요구사항을 파악해보는건 처음이네요. 그리고 진&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;요구 사항&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kitchenpos&lt;span&gt;&amp;nbsp;&lt;/span&gt;패키지의 코드를 보고 키친포스의 요구 사항을&lt;span&gt;&amp;nbsp;&lt;/span&gt;README.md에 작성한다.&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;a href=&quot;https://dooray.com/htmls/guides/markdown_ko_KR.html&quot;&gt;마크다운(Markdown) - Dooray!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레거시 코드를 분석해 요구사항을 파악하는 미션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드만으로 어떻게 요구사항을 정리하냐고 생각할 수 있지만 제공되는 파일 중에는 .http, .sql 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GB5F9/btrP3TKA0wx/jOHKdrk8zaCnnhTsLIfp0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GB5F9/btrP3TKA0wx/jOHKdrk8zaCnnhTsLIfp0K/img.png&quot; data-alt=&quot;요구사항 분석에 도움이 되는 파일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GB5F9/btrP3TKA0wx/jOHKdrk8zaCnnhTsLIfp0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGB5F9%2FbtrP3TKA0wx%2FjOHKdrk8zaCnnhTsLIfp0K%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;481&quot; height=&quot;444&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;요구사항 분석에 도움이 되는 파일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1667224033479&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;menus.http 파일

###
POST {{host}}/api/menus
Content-Type: application/json

{
  &quot;name&quot;: &quot;후라이드+후라이드&quot;,
  &quot;price&quot;: 19000,
  &quot;menuGroupId&quot;: &quot;f1860abc-2ea1-411b-bd4a-baa44f0d5580&quot;,
  &quot;displayed&quot;: true,
  &quot;menuProducts&quot;: [
    {
      &quot;productId&quot;: &quot;3b528244-34f7-406b-bb7e-690912f66b10&quot;,
      &quot;quantity&quot;: 2
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1667224059338&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE orders (
    id BIGINT(20) NOT NULL AUTO_INCREMENT,
    order_table_id BIGINT(20) NOT NULL,
    order_status VARCHAR(255) NOT NULL,
    ordered_time DATETIME NOT NULL,
    PRIMARY KEY (id)
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고하면서 파악하면 아래와 같은 요구사항을 뽑아낼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1667224763304&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 키친포스

## 요구 사항
간단한 식당 관리 앱을 구현한다.
메뉴와 상품, 주문(배달, 포장, 취식), 테이블로 구성된다.

### 메뉴 그룹
- [] 사용자가 보는 메뉴그룹을 생성한다.
    - [] 메뉴그룹명은 반드시 한글자 이상 입력해야 한다.
    - [] 메뉴그룹명은 중복이 가능하다.
- [] 등록된 메뉴그룹 내역을 확인할 수 있다.

...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 파악하다보면 유효성 체크에서 이상한 부분이 있어서 궁금해서 질문했는데&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;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yOoKO/btrP8N4ipNC/t51j7w7Hjs7FoCBBTaNiE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yOoKO/btrP8N4ipNC/t51j7w7Hjs7FoCBBTaNiE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yOoKO/btrP8N4ipNC/t51j7w7Hjs7FoCBBTaNiE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyOoKO%2FbtrP8N4ipNC%2Ft51j7w7Hjs7FoCBBTaNiE0%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;246&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 레거시에서 쉽게 접할 수 있는 오류 케이스였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요구사항을 문서화했으면 이번 단계는 끝난다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3단계 - 테스트 코드를 통한 코드 보호&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1667225252438&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;Step3 - 테스트를 통한 코드 보호 by loop-study &amp;middot; Pull Request #162 &amp;middot; next-step/ddd-legacy&quot; data-og-description=&quot;안녕하세요 박현철입니다. Mockito, @WebMvcTest 등 처음 접해서 학습하고 테스트 작성하는데 시간이 걸렸습니다. (삽질 좀 많이했습니다...) 아직 부족하지만 제출합니다.   피드백 부탁드립니다. &quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/ddd-legacy/pull/162&quot; data-og-url=&quot;https://github.com/next-step/ddd-legacy/pull/162&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ncPfs/hyQpqGOcid/kE7Kk51GOR7MMvagooti21/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/next-step/ddd-legacy/pull/162&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/ddd-legacy/pull/162&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ncPfs/hyQpqGOcid/kE7Kk51GOR7MMvagooti21/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;Step3 - 테스트를 통한 코드 보호 by loop-study &amp;middot; Pull Request #162 &amp;middot; next-step/ddd-legacy&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 박현철입니다. Mockito, @WebMvcTest 등 처음 접해서 학습하고 테스트 작성하는데 시간이 걸렸습니다. (삽질 좀 많이했습니다...) 아직 부족하지만 제출합니다.   피드백 부탁드립니다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;요구 사항&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정리한 키친포스의 요구 사항을 토대로 테스트 코드를 작성한다.&lt;/li&gt;
&lt;li&gt;모든 Business Object에 대한 테스트 코드를 작성한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@SpringBootTest를 이용한 통합 테스트 코드&lt;/li&gt;
&lt;li&gt;또는&lt;span&gt;&amp;nbsp;&lt;/span&gt;@ExtendWith(MockitoExtension.class)를 이용한 단위 테스트 코드를 작성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Controller에 대한 테스트 코드 작성은 권장하지만 필수는 아니다.&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;a href=&quot;https://www.baeldung.com/spring-boot-testing&quot;&gt;Testing in Spring Boot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레거시에 테스트 코드를 붙이는 미션으로 이전에 비해 많은 어려움을 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 테스트 코드를 작성하는 방법을 다양화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Mockito를 활용한 Mock 테스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Web Layer 테스트를 위한 @WebMvcTest&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 실객체를 상속받아 구현하는 Fake 객체&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 테스트 픽스처(Test Fixture)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단위 테스트만 알던 나에게&amp;nbsp;생소한 게 개념이라 구글링으로 찾아보고 간단히 학습한 뒤 진행했지만 테스트 코드 작성에 시간이 오래 걸렸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgDIL2/btrP8NQ6pLy/PWvouiPsbXaAgsVsDMYBfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgDIL2/btrP8NQ6pLy/PWvouiPsbXaAgsVsDMYBfK/img.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;922&quot; data-is-animation=&quot;false&quot; width=&quot;440&quot; height=&quot;663&quot; data-widthpercent=&quot;37.05&quot; style=&quot;width: 36.61516169891106%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgDIL2/btrP8NQ6pLy/PWvouiPsbXaAgsVsDMYBfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgDIL2%2FbtrP8NQ6pLy%2FPWvouiPsbXaAgsVsDMYBfK%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;612&quot; height=&quot;922&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l5aSz/btrQas55gfp/BEDUr0K70fs1JZzfcnmYJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l5aSz/btrQas55gfp/BEDUr0K70fs1JZzfcnmYJ0/img.png&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;1172&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;62.95&quot; style=&quot;width: 62.222047603414524%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l5aSz/btrQas55gfp/BEDUr0K70fs1JZzfcnmYJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl5aSz%2FbtrQas55gfp%2FBEDUr0K70fs1JZzfcnmYJ0%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;1322&quot; height=&quot;1172&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;146개의 테스트 케이스가 나왔다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트를 작성하는데 일주일이 넘게 걸렸지만, 덕분에 여러가지 테스트 방법을 알아보고 사용해보면서 서로 무엇이 다른지 경험해보는 시간이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히, 테스트를 작성할수록 테스틑 코드가 꼬이는 걸 경험했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;공통적으로 사용되는 테스트 데이터를 Fixture로 분리하니 처음엔 편했는데&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성되는 테스트가 많아질수록 복잡도가 높아지고&amp;nbsp;Data Set을 수정하면 연관된 테스트 코드 모두가 실패했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 문제의 FixtureData 코드다.&lt;/p&gt;
&lt;pre id=&quot;code_1667293803316&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class FixtureData {

    protected List&amp;lt;MenuGroup&amp;gt; menuGroups = new ArrayList&amp;lt;&amp;gt;();
    protected List&amp;lt;Product&amp;gt; products = new ArrayList&amp;lt;&amp;gt;();
    protected List&amp;lt;Menu&amp;gt; menus = new ArrayList&amp;lt;&amp;gt;();
    protected List&amp;lt;MenuProduct&amp;gt; menuProducts = new ArrayList&amp;lt;&amp;gt;();
    protected List&amp;lt;OrderTable&amp;gt; orderTables = new ArrayList&amp;lt;&amp;gt;();
    protected List&amp;lt;OrderLineItem&amp;gt; orderLineItems = new ArrayList&amp;lt;&amp;gt;();
    protected List&amp;lt;Order&amp;gt; orders = new ArrayList&amp;lt;&amp;gt;();

    protected static final UUID FIRST_ID = UUID.randomUUID();
    protected static final UUID SECOND_ID = UUID.randomUUID();

    protected static final Boolean MENU_HIDE = false;
    protected static final Boolean MENU_SHOW = true;

    protected static final Boolean TABLE_CLEAR = true;
    protected static final Boolean TABLE_SIT = false;
    protected static final int TABLE_DEFAULT_NUMBER_OF_GUEST = 0;

    protected static final ObjectMapper objectMapper = new ObjectMapper();

    protected void fixtureMenuGroups() {
        setMenuGroups();
    }

    protected void fixtureProducts() {
        setMenuGroups();
        setProducts();
        setMenuProducts();
        setMenus();
    }

    protected void fixtureMenus() {
        setMenuGroups();
        setProducts();
        setMenuProducts();
        setMenus();
    }

    protected void fixtureOrderTables() {
        setOrderTables();
    }

    protected void fixtureOrders() {
        setMenuGroups();
        setProducts();
        setMenuProducts();
        setMenus();
        setOrderTables();
        setOrderLineItems();
        setOrders();
    }

    private void setMenuGroups() {
        MenuGroup menuGroup = new MenuGroup();
        menuGroup.setId(FIRST_ID);
        menuGroup.setName(&quot;추천메뉴&quot;);

        MenuGroup menuGroup2 = new MenuGroup();
        menuGroup2.setId(SECOND_ID);
        menuGroup2.setName(&quot;중식&quot;);

        menuGroups.add(menuGroup);
        menuGroups.add(menuGroup2);
    }

    private void setProducts() {
        Product product = new Product();
        product.setId(FIRST_ID);
        product.setPrice(ofPrice(1000));
        product.setName(&quot;후라이드&quot;);

        Product product2 = new Product();
        product2.setId(SECOND_ID);
        product2.setPrice(ofPrice(1100));
        product2.setName(&quot;양념&quot;);

        products.add(product);
        products.add(product2);
    }

    private void setMenuProducts() {
        MenuProduct menuProduct = new MenuProduct();
        menuProduct.setSeq(1L);
        menuProduct.setProduct(products.get(0));
        menuProduct.setQuantity(1L);

        MenuProduct menuProduct2 = new MenuProduct();
        menuProduct2.setSeq(2L);
        menuProduct2.setProduct(products.get(1));
        menuProduct2.setQuantity(1L);

        menuProducts.add(menuProduct);
        menuProducts.add(menuProduct2);
    };

    private void setMenus() {
        Menu menu = new Menu();
        menu.setId(FIRST_ID);
        menu.setMenuGroup(menuGroups.get(0));
        menu.setName(&quot;점심 한정&quot;);
        menu.setPrice(ofPrice(900));
        menu.setDisplayed(MENU_SHOW);
        menu.setMenuProducts(Arrays.asList(menuProducts.get(0)));

        Menu menu2 = new Menu();
        menu2.setId(SECOND_ID);
        menu2.setMenuGroup(menuGroups.get(1));
        menu2.setName(&quot;저녁 한정&quot;);
        menu2.setPrice(ofPrice(1000));
        menu2.setDisplayed(MENU_SHOW);
        menu2.setMenuProducts(Arrays.asList(menuProducts.get(1)));

        menus.add(menu);
        menus.add(menu2);
    }

    private void setOrderTables() {
        OrderTable orderTable = new OrderTable();
        orderTable.setName(&quot;1번&quot;);
        orderTable.setId(FIRST_ID);
        orderTable.setEmpty(TABLE_CLEAR);
        orderTable.setNumberOfGuests(TABLE_DEFAULT_NUMBER_OF_GUEST);

        OrderTable orderTable2 = new OrderTable();
        orderTable2.setName(&quot;2번&quot;);
        orderTable2.setId(SECOND_ID);
        orderTable2.setEmpty(TABLE_CLEAR);
        orderTable2.setNumberOfGuests(TABLE_DEFAULT_NUMBER_OF_GUEST);

        orderTables.add(orderTable);
        orderTables.add(orderTable2);
    }

    private void setOrderLineItems() {
        OrderLineItem orderLineItem = new OrderLineItem();
        orderLineItem.setMenu(menus.get(0));
        orderLineItem.setQuantity(1);
        orderLineItem.setPrice(menus.get(0).getPrice());

        orderLineItems.add(orderLineItem);
    };

    private void setOrders() {
        Order order = new Order();
        order.setId(FIRST_ID);
        order.setType(OrderType.EAT_IN);
        order.setStatus(OrderStatus.WAITING);
        order.setOrderDateTime(LocalDateTime.now());
        order.setOrderLineItems(orderLineItems);
        order.setOrderTable(orderTables.get(0));

        Order order2 = new Order();
        order2.setId(SECOND_ID);
        order2.setType(OrderType.DELIVERY);
        order2.setStatus(OrderStatus.WAITING);
        order2.setOrderDateTime(LocalDateTime.now());
        order2.setOrderLineItems(orderLineItems);
        order2.setDeliveryAddress(&quot;대한민국 어딘가&quot;);

        orders.add(order);
        orders.add(order2);
    }

    protected BigDecimal ofPrice(int price) {
        return BigDecimal.valueOf(price);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한눈에 봐도 복잡한 게 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 도메인 데이터를 하나의 픽스쳐로 사용하려고 했다가 무서운 괴물이 되어버렸다. (도메인에 맞게&amp;nbsp;Fixture를 분리하자.)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전까지 단위 테스트 경험만 있어서 테스트 코드 관리에 자세히 고민해본 적도 없었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덕분에 테스트 코드 관리를 어떻게 해야 할지 고민하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 요구사항에 맞게 테스트 케이스를 다 작성했으면 1주차는 마무리된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;참고하면 좋은 정보&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1667467213669&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;'개발 &amp;amp; 방법론/DDD' 카테고리의 글 목록&quot; data-og-description=&quot;오늘도 공부하자&quot; data-og-host=&quot;loopstudy.tistory.com&quot; data-og-source-url=&quot;https://loopstudy.tistory.com/category/개발%20%26%20방법론/DDD&quot; data-og-url=&quot;https://loopstudy.tistory.com/category/%EA%B0%9C%EB%B0%9C%20&amp;amp;%20%EB%B0%A9%EB%B2%95%EB%A1%A0/DDD&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bCIUmd/hyQsfEvHSt/IZ9yvyQKo3qu0fslAvYWE0/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/hfFbp/hyQqSqCk2Q/TDBZh8k2hX4oxTBloX4JT1/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/b4zz2C/hyQqK0q9sM/KQoTu83DbtPuCSlKhdJRPk/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960&quot;&gt;&lt;a href=&quot;https://loopstudy.tistory.com/category/개발%20%26%20방법론/DDD&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://loopstudy.tistory.com/category/개발%20%26%20방법론/DDD&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bCIUmd/hyQsfEvHSt/IZ9yvyQKo3qu0fslAvYWE0/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/hfFbp/hyQqSqCk2Q/TDBZh8k2hX4oxTBloX4JT1/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/b4zz2C/hyQqK0q9sM/KQoTu83DbtPuCSlKhdJRPk/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;'개발 &amp;amp; 방법론/DDD' 카테고리의 글 목록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘도 공부하자&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;loopstudy.tistory.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_1667467225694&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;JUnit5 알아보기&quot; data-og-description=&quot;인텔리제이를 사용하는 자바 개발자가 90% 이상 사용한다는 JUnit을 간단히 알아보러 한다. 자세한 내용은 공식 가이드를 참고하기 바란다. JUnit 5 JUnit이란? JUnit은 자바 프로그래밍 언어용 유닛 테&quot; data-og-host=&quot;loopstudy.tistory.com&quot; data-og-source-url=&quot;https://loopstudy.tistory.com/279&quot; data-og-url=&quot;https://loopstudy.tistory.com/279&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/HVVB4/hyQshI6G52/aIYzgO4pmjkUk15OyhS0ok/img.jpg?width=800&amp;amp;height=464&amp;amp;face=0_0_800_464,https://scrap.kakaocdn.net/dn/b5n24V/hyQqNQoIcS/76R5g1PuKDmOUbMBJjOuEK/img.jpg?width=800&amp;amp;height=464&amp;amp;face=0_0_800_464,https://scrap.kakaocdn.net/dn/RYRBk/hyQqJ8iW7G/X6kRIg0M8Dul5I4Lb0r5z1/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960&quot;&gt;&lt;a href=&quot;https://loopstudy.tistory.com/279&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://loopstudy.tistory.com/279&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/HVVB4/hyQshI6G52/aIYzgO4pmjkUk15OyhS0ok/img.jpg?width=800&amp;amp;height=464&amp;amp;face=0_0_800_464,https://scrap.kakaocdn.net/dn/b5n24V/hyQqNQoIcS/76R5g1PuKDmOUbMBJjOuEK/img.jpg?width=800&amp;amp;height=464&amp;amp;face=0_0_800_464,https://scrap.kakaocdn.net/dn/RYRBk/hyQqJ8iW7G/X6kRIg0M8Dul5I4Lb0r5z1/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960');&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;JUnit5 알아보기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인텔리제이를 사용하는 자바 개발자가 90% 이상 사용한다는 JUnit을 간단히 알아보러 한다. 자세한 내용은 공식 가이드를 참고하기 바란다. JUnit 5 JUnit이란? JUnit은 자바 프로그래밍 언어용 유닛 테&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;loopstudy.tistory.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_1667467246196&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Mockito 알아보기 (부제 : BDD)&quot; data-og-description=&quot;테스트 코드 입문자라면 겪어보는 문제 테스트 코드를 작성한지 얼마 안 되었을 때 의존성이 있는 객체의 테스트 코드를 작성하면서, 의존하는 객체의 실제 인스턴스를 생성해서 진행한 적이 &quot; data-og-host=&quot;loopstudy.tistory.com&quot; data-og-source-url=&quot;https://loopstudy.tistory.com/315&quot; data-og-url=&quot;https://loopstudy.tistory.com/315&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jwrCj/hyQqKTHpd5/AGCnNw8d1nVz2GUoiTslD1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/baLa6G/hyQsjfQFOw/x8t1cn7STs1S58doUzoFo1/img.png?width=1352&amp;amp;height=766&amp;amp;face=0_0_1352_766&quot;&gt;&lt;a href=&quot;https://loopstudy.tistory.com/315&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://loopstudy.tistory.com/315&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jwrCj/hyQqKTHpd5/AGCnNw8d1nVz2GUoiTslD1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/baLa6G/hyQsjfQFOw/x8t1cn7STs1S58doUzoFo1/img.png?width=1352&amp;amp;height=766&amp;amp;face=0_0_1352_766');&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;Mockito 알아보기 (부제 : BDD)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;테스트 코드 입문자라면 겪어보는 문제 테스트 코드를 작성한지 얼마 안 되었을 때 의존성이 있는 객체의 테스트 코드를 작성하면서, 의존하는 객체의 실제 인스턴스를 생성해서 진행한 적이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;loopstudy.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>교육 및 인강/DDD 세레나데</category>
      <category>DDD</category>
      <category>DDD 세레나데</category>
      <category>Domain Driven Design</category>
      <category>Domain-Driven Design</category>
      <category>mockito</category>
      <category>nextstep</category>
      <category>도메인 주도 설계</category>
      <category>테스트 코드</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/447</guid>
      <comments>https://loopstudy.tistory.com/447#entry447comment</comments>
      <pubDate>Tue, 1 Nov 2022 19:29:48 +0900</pubDate>
    </item>
    <item>
      <title>DDD 세레나데 시작하면서...</title>
      <link>https://loopstudy.tistory.com/344</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;NEXTSTEP에서 진행하는 교육과정&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;DDD 세레나데 2기&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1667197607133&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;DDD(Domain-Driven Design) 세레나데&quot; data-og-description=&quot;&quot; data-og-host=&quot;edu.nextstep.camp&quot; data-og-source-url=&quot;https://edu.nextstep.camp/s/W08ac6g9&quot; data-og-url=&quot;https://edu.nextstep.camp/c/GwN2MSqv&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/vF0Yc/hyQpu9OGW0/EQT4E0nnusZfYYmKL4GkKk/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565,https://scrap.kakaocdn.net/dn/MCcc9/hyQn3MNszr/kjKzN1R2GHf7URKFVKoopK/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565&quot;&gt;&lt;a href=&quot;https://edu.nextstep.camp/s/W08ac6g9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://edu.nextstep.camp/s/W08ac6g9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/vF0Yc/hyQpu9OGW0/EQT4E0nnusZfYYmKL4GkKk/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565,https://scrap.kakaocdn.net/dn/MCcc9/hyQn3MNszr/kjKzN1R2GHf7URKFVKoopK/img.jpg?width=968&amp;amp;height=565&amp;amp;face=0_0_968_565');&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;DDD(Domain-Driven Design) 세레나데&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;edu.nextstep.camp&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교육을 수강한 지 1년이 지났지만, 이제야 후기를 작성한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;수강 이유&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1667197876077&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;TDD, 클린 코드 with Java&quot; data-og-description=&quot;&quot; data-og-host=&quot;edu.nextstep.camp&quot; data-og-source-url=&quot;https://edu.nextstep.camp/s/ApJ4Ca71&quot; data-og-url=&quot;https://edu.nextstep.camp/c/8fWRxNWU&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/MONJ1/hyQn5cOJiP/8F9DAGULnOG7DngRLpqwfk/img.jpg?width=900&amp;amp;height=600&amp;amp;face=0_0_900_600&quot;&gt;&lt;a href=&quot;https://edu.nextstep.camp/s/ApJ4Ca71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://edu.nextstep.camp/s/ApJ4Ca71&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/MONJ1/hyQn5cOJiP/8F9DAGULnOG7DngRLpqwfk/img.jpg?width=900&amp;amp;height=600&amp;amp;face=0_0_900_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;TDD, 클린 코드 with Java&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;edu.nextstep.camp&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TDD, 클린코드 11기를 수강하고 나서 객체지향을 알게 되었고, 서적과 스터디로 오브젝트 등을 읽으면서 객체지향을 좀 더 알아가고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시 21년 하반기에 취업목표를 생각하고 있었고, 구인 공고를 찾아봤더니&amp;nbsp;&lt;b&gt;DDD, MSA&lt;/b&gt; 용어가 많이 보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커뮤니티 게시글이나 스터디 모집에서 DDD가 많이 보였고, 지인들도 DDD 스터디를 구한다고 했었다.&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;관심이 생겼지만, 커뮤니티에서 DDD, MSA는 난이도가 높아 나중에 공부하는 게 좋다는 말이 있어서 관심을 접으려고 했는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여름이 될 무렵에 NEXTSTEP에서 DDD 세레나데 모집공고가 올라와서 호기심에 확인해보니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 회사에서 겪었던 문제를 언급하고 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;922&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xsWQB/btrPU0jMTXz/cLzjP3m9bhHQO8fLIZ2CD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xsWQB/btrPU0jMTXz/cLzjP3m9bhHQO8fLIZ2CD1/img.png&quot; data-alt=&quot;DDD 세레나데에서 다루는 내용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xsWQB/btrPU0jMTXz/cLzjP3m9bhHQO8fLIZ2CD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxsWQB%2FbtrPU0jMTXz%2FcLzjP3m9bhHQO8fLIZ2CD1%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;1432&quot; height=&quot;922&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;922&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DDD 세레나데에서 다루는 내용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 같은 단어지만 구성원간 의미하는 바가 달라서 서로 어긋난 경우가 많았고 (같은&amp;nbsp;영업팀도 파벌에 따라 달랐다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요구사항을 이해하려고 여러명에게 돌아가면서 같은 질문을 한 적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발환경은 레거시에 절차지향 방식이라 DB 중심이고&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;경험했던 문제들이 언급되고, 교육도 1년 만에 연다고 하니 한정판 구매한다는 느낌으로 수강 신청했다.&amp;nbsp;&lt;i&gt;(2분 만에 수강신청이 끝났다.)&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;1년이 지난 지금 작성한 이유는 교육 난이도와 객체지향이 많이 미숙한 상태에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDD 개념을 다 이해하기도 힘들었고 억지로 교육을 밀다 보니 후기를 작성하기엔 많이 미흡해서 이제야 작성한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;강의 내용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDD 세레나데에서 제공하는 강의 특징과 커리큘럼이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1886&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjSTjY/btrP4tRwMi0/HtQHYZ7p84QzfJ85LmnKjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjSTjY/btrP4tRwMi0/HtQHYZ7p84QzfJ85LmnKjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjSTjY/btrP4tRwMi0/HtQHYZ7p84QzfJ85LmnKjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjSTjY%2FbtrP4tRwMi0%2FHtQHYZ7p84QzfJ85LmnKjk%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;1886&quot; height=&quot;714&quot; data-origin-width=&quot;1886&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1688&quot; data-origin-height=&quot;1728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cctAD0/btrP0g0wQ0f/Yc23Mfl0YIEyc0WelmSDg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cctAD0/btrP0g0wQ0f/Yc23Mfl0YIEyc0WelmSDg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cctAD0/btrP0g0wQ0f/Yc23Mfl0YIEyc0WelmSDg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcctAD0%2FbtrP0g0wQ0f%2FYc23Mfl0YIEyc0WelmSDg1%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;1688&quot; height=&quot;1728&quot; data-origin-width=&quot;1688&quot; data-origin-height=&quot;1728&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>교육 및 인강/DDD 세레나데</category>
      <category>DDD</category>
      <category>DDD 세레나데</category>
      <category>Domain Driven Design</category>
      <category>nextstep</category>
      <category>도메인 주도 설계</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/344</guid>
      <comments>https://loopstudy.tistory.com/344#entry344comment</comments>
      <pubDate>Mon, 31 Oct 2022 16:50:34 +0900</pubDate>
    </item>
    <item>
      <title>9월 회고 및 목표</title>
      <link>https://loopstudy.tistory.com/442</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;텐션이 다시 올라온 9월&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;9월은&amp;nbsp;구직 준비를 위해 이력서를 작성하고 NEXTSTEP 멘토링으로 이력서 피드백을 받고 수정하면서 회사에 넣을 준비를 했고,&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;진행 중이던 클린 코드, 이펙티브 자바 스터디가 무난하게 끝나고 다음 서적을 정했으며,&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt; 정리 못했던 교육 정리와 면접 준비를 하면서&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;잃어버린 텐션이 다시 올라오기 시작한 9월이었다......&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는 사실 희망사항일 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;i&gt;&lt;b&gt;지난 9월은 시간이 어떻게 흘려갔는지 정신이 없었다.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p 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;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;NEXTSTEP 멘토링 - 1차, 2차 미팅&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추석 전에&amp;nbsp;1차 미팅을 진행하면서 멘토님에게 이력서 기반으로 자기소개와 경력 소개를 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 당시 이력서의 내용 일부분이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1580&quot; data-origin-height=&quot;1082&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K3G01/btrOkTlGTMB/J1QmwQD8Rkf7vwlSmDdKl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K3G01/btrOkTlGTMB/J1QmwQD8Rkf7vwlSmDdKl0/img.png&quot; data-alt=&quot;맨 처음에 작성했던 이력서 형태.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K3G01/btrOkTlGTMB/J1QmwQD8Rkf7vwlSmDdKl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK3G01%2FbtrOkTlGTMB%2FJ1QmwQD8Rkf7vwlSmDdKl0%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;1580&quot; height=&quot;1082&quot; data-origin-width=&quot;1580&quot; data-origin-height=&quot;1082&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;나는 SI/SM 진행했지만 하나의 플랫폼을 구축하고 운영했기 때문에 회사단위로 경력서를 작성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XXX 유지보수의&amp;nbsp;기간은 입사한 달 ~ 퇴사한 달로 1월부터 6월까지 진행했다는 의미로 작성했었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 담당 업무가 그 기간 동안 진행했던 프로젝트를 정리했지만, 아래와 같은&amp;nbsp;피드백을 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 작성자 본인만 이해할 수 있는 내용이다. 다른 사람은 무슨 말인지 전혀 이해가 안 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- XXX 유지 보수가 하나의 플젝으로 보인다. 아래의 담당 업무는 오히려 하나의 플젝에서 담당한 업무밖에 인식이 안된다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 프로젝트 기간과 개발자 몇 명인지 표시해둘 것.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 글쓰기 연습이 필요해 보인다. 표준어로 작성할 것.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 10년 뒤에 어떤 개발자가 되어있을지 생각해봤는가?&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외 피드백과 참고용 이력서를 받으면서&amp;nbsp;1차 미팅을 종료했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차 미팅은 추석 이후에 진행했는데, 다음은 이력서 수정본 일부분이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lMFmy/btrOmr2GI5t/yztBJBrue5NSHTtQGK8Dl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lMFmy/btrOmr2GI5t/yztBJBrue5NSHTtQGK8Dl1/img.png&quot; data-alt=&quot;1차에 비해 많이 개선되었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lMFmy/btrOmr2GI5t/yztBJBrue5NSHTtQGK8Dl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlMFmy%2FbtrOmr2GI5t%2FyztBJBrue5NSHTtQGK8Dl1%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;1434&quot; height=&quot;1032&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1차에 비해 많이 개선되었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이력서를 수정하면서 1차에 비해 많이 좋아졌다고 느껴졌지만, 2차 미팅을 통해 이전 못지않게 많은 피드백을 받게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 비즈니스 용어는 사용하지 마라, 단일 책임 원칙을 적용한 중복 제거 or 코드 품질 향상처럼 기술적인 용어를 찾아서 변경해라 이력서를 보는 사람은 개발자다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 프로젝트마다 기술환경이 동일해도 적어라&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 프로젝트 기간이 한두 달로 짧으면 크게 묶어서 1차 개편, 2차 개편 등으로 구분하고 내부에서 프로젝트를 구분해서 보여줘라. 프로젝트 사이 공백 기간에 유지보수를 적어도 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 쉬는 기간도 경력이 되는 이벤트(&lt;b&gt;오픈소스 참여 or NEXTSTEP 교육 등)&lt;/b&gt;가 필요하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- *&lt;span style=&quot;color: #ee2323;&quot;&gt;문제 &amp;gt; 원인 &amp;gt; 해결책 &amp;gt; 개선 효과로 정리하면 좋다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- *&lt;span style=&quot;color: #ee2323;&quot;&gt;어떤 개발자가 되고 싶은가? (상세한 커리어, 철학적으로 생각해보기)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 피드백은 지난 1차 미팅에서도 나왔던 이야기인데, 처음에는 철학적으로 생각해야 하는 줄 알고 제대로 답변하지도 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에도 같은 질문인 줄 알았는데, 어떤 커리어를 갖고 싶은지 물어보신 거였다. (철학적인 것도 생각하면 좋다고 하셨다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차 미팅은 여기까지 진행되었고, 다음 마지막 3차 미팅은 이력서 수정본이 완성되면 (2주 뒤에 제출하기로 했다) 날짜를 잡기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 예상치 못한 일이 터지면서 2차 미팅한 지 한 달이나 지났는데도 이력서를 수정하지 못했다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예상치 못한 사건_1 - &amp;nbsp;&lt;i&gt;목디스크&lt;/i&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차 미팅이 끝나고 얼마 안돼서 어머니가 목디스크가 크게 터지는 일이 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;움직일 수 없을 정도로 왼쪽 어깨, 등, 팔 전체에 저림과 통증으로 잠자는 것도 힘들 정도로 상태는 안 좋았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠자는 것도 옆에서 계속 찜질팩으로 찜질하고 팔을 마사지해야 통증이 조금 완화되어 눈을 붙일 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pG1NU/btrOrevbbHg/BNc8pN2GhwnMtf97V5dKkk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pG1NU/btrOrevbbHg/BNc8pN2GhwnMtf97V5dKkk/img.jpg&quot; data-alt=&quot;목디스크 증상 부위 [출처,자생의료재단]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pG1NU/btrOrevbbHg/BNc8pN2GhwnMtf97V5dKkk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpG1NU%2FbtrOrevbbHg%2FBNc8pN2GhwnMtf97V5dKkk%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;880&quot; height=&quot;550&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;550&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;옆동네에 이름이 있는 A병원도 간신히 방문하고 물리치료와 목 견인기를 받으면서 상태가 좋아지길 기다렸지만, 증상이 호전되지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목디스크에 좋은 자세나 스트레칭을 찾아보긴 했지만 마땅한 스트레칭도 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유튜버 영상을 찾아도 정상적인 사람에게만 효과 있고 이미 목디스크가 발생한 사람에게는 위험한 스트레칭이더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사흘간 변화가 없자, 다른 병원이나 한의원도 알아보다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 어머니가 입원했던 동네 B병원을 찾아갔더니 A병원보다 시설과 치료가 더 좋았다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B병원을 다니면서 하루가 지날 때마다&amp;nbsp;상태가 호전되는 게 보이기 시작했고, 밤에 잠드는 시간도 조금씩 늘어났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 어머니가 제대로 된 잠을 청하기까지 2주의 시간이 걸렸다. &lt;b&gt;(*목디스크가 허리디스크에 비해서 회복 속도가 빠르다고 한다.)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그제야 나도 긴장의 끈을 놓을 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예상치 못한 사건_2 - &lt;i&gt;이석증&lt;/i&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴장의 끈을 놓은 지 이틀이 된 토요일 오후 2~3시 침대에서 뒤척이다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갑자기 세상이 빙글빙글 돌기 시작했다. &lt;b&gt;(@.@) ?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순간 현기증인 줄 알고 가만히 기다렸더니 증상이 완화돼서 별거 아닌가 싶었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고개를 옆으로 움직이는 순간 세상이 다시 빙그르르르르르르르르르르르르르 @@@@@@@@@@@@@@@~~~~~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;침대에서 일어나려고 했지만 세상이 막 움직이면서 몸이 저절로 침대에 눕혀졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현기증처럼 머리가 둔해지고 무거워지는 어지러움은 처음이었다. 얼마나 어지럽던지 미약한 구토 증상까지 나타났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 특정 자세에서 어지럼증이 심해지는 것을 파악되어 올바른 자세로 증상이 사라지길 기다렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누운 상태로 구글링을 해보니 이석증이란 증상과 흡사해서 곧바로 응급실을 찾아갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응급실 가는 것도 꽤 많은 고역을 치웠다. 병원은 차 타고 금방 가는데 어지럼증이 심해서 차멀미가 왜 이리 나는지 짧지만 매우 긴 시간을 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간신히 병원에 도착해서 접수하고 잠깐의 대기를 타고 응급실에 들어갈 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병원 침대에서 잠깐의 대기 후 의사 선생님이 오셔서 진찰을 했는데 방법이 간단했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;침대에 앉은 상태로 얼굴을 45도로 틀고 그대로 빠르게 눕힌 뒤 잠시 뒤&amp;nbsp;내 눈앞에 손가락을 두더니 손가락에 초점을 맞춰보라고 하셨는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초점을 맞추긴 했지만, 계속 초점이 흔들렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 방법을 좌우로 몇 번 반복하더니 이석증이 같다고 하셨다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/69in3/btrOtGLClP7/C0JkSvrDrMT5YcpxKMIiL1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/69in3/btrOtGLClP7/C0JkSvrDrMT5YcpxKMIiL1/img.jpg&quot; data-alt=&quot;이석증이란? [출처, 하이닥]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/69in3/btrOtGLClP7/C0JkSvrDrMT5YcpxKMIiL1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F69in3%2FbtrOtGLClP7%2FC0JkSvrDrMT5YcpxKMIiL1%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;550&quot; height=&quot;550&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이석증이란? [출처, 하이닥]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고 봤더니 이석증은 증상 때문에 눈이 무의식적으로 떨려서 제대로 초점을 못 맞춘다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 혈액검사와 다른 검사를 더 진행하고 어지럼증을 완화시켜주는 수액을 맞았다. (다른 검사 결과는 정상이라고 하신다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FLLrA/btrOnLVNElB/0H0u8cRCvOXeyZEOXbzOx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FLLrA/btrOnLVNElB/0H0u8cRCvOXeyZEOXbzOx0/img.png&quot; data-alt=&quot;응급실에서 수액을 맞았다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FLLrA/btrOnLVNElB/0H0u8cRCvOXeyZEOXbzOx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFLLrA%2FbtrOnLVNElB%2F0H0u8cRCvOXeyZEOXbzOx0%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;1440&quot; height=&quot;1080&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&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;수액을 맞은 뒤 어지럼증이 꽤 완화되었고, 어지러울 때 먹는 상비약 3일 치를 처방해주면서&amp;nbsp;집에서 2,3일간 푹 쉬라고 하셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주말이 끝나고 상태를 한번 더 확인하기 위해 신경외과도 예약했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응급실을 다녀오고 나서 집에서 바른 자세로 아무것도 안 하고 누워만 있었다가,&amp;nbsp;지루해서 스마트폰도 몇 번 만지작거렸는데 고개가 흔들려서 어지럼증 때문에 제대로 할 수가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고개가 흔들리지 않도록 어머니가 쓰셨던 목보호대를 내가 착용하기 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 하루가 다르게 좋아지는 게 느껴져서 공휴일이었던 월요일에는 누워서 스마트폰도 할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 날 병원에 갈 때는 상태가 좋아졌다. 택시 타고 가는데도 이전과 다르게 차멀미가 없고 멀쩡했으며, 천천히 움직이면 어지럼증이 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병원에서 의사 선생님이 말하길,&amp;nbsp;응급실에 왔을 때랑 비교하면 많이 좋아지고 있기 때문에 천천히 행동만 하고 급격한 움직임을 조심하면 2~4주면 회복이 될 거라 하셨다. 이전처럼 상비약 7일치를 처방받고 병원을 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 뒤늦게 NEXTSTEP 멘토님에게 사정을 말씀드릴 수 있었다.&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;회고록을 작성하는 지금은 이석증 걸린 지 12일이 되었는데&amp;nbsp;급격한 행동을 비롯하여 특정 자세 몇 가지만 조심하면 일상생활하는 데 전혀 무리가 없을 정도로 회복이 되었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;진행 중인 스터디는...&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 사건 때문에 클린 코드 &amp;amp; 이펙티브 자바 스터디 막바지에 제대로 참여도 못하고 듣기만 했지만, 시간 나면 따로 진행할 생각이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;우선 다음 서적으로 흥미로운 여러 가지 서적이 언급이 되었지만 투표를 통해 서적을 정했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;1200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MITxJ/btrOrRUE08z/3P5dknDDKKYwduudZJLkk0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MITxJ/btrOrRUE08z/3P5dknDDKKYwduudZJLkk0/img.jpg&quot; data-alt=&quot;새가 예쁘다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MITxJ/btrOrRUE08z/3P5dknDDKKYwduudZJLkk0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMITxJ%2FbtrOrRUE08z%2F3P5dknDDKKYwduudZJLkk0%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;554&quot; height=&quot;712&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;새가 예쁘다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이번 10월부터는?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 이번 달은 크게 2가지 중심으로 진행할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NEXTSTEP 멘토링 완주&lt;/b&gt; - 이력서에 피드백을 반영하고 마지막 3차 미팅을 진행할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지원 및 면접 준비&lt;/b&gt; - 멘토링이 끝나고 나서 3일 안에 이력서를 넣을 예정이다. 복습하면서 준비를 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 학습방식을 변경할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽은 서적은 많지만 블로그에 정리된 책은 몇 권 없다. 읽고 넘어간 책만 수두룩하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;챕터마다 읽은 뒤 간략히 정리 포스팅을 진행할 필요성이 느껴지는데, 간단하게 일일 목표에 정리하고 추후에 해당 태그를 찾아 정리에 활용할 생각이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>목표 및 회고</category>
      <category>10월 목표</category>
      <category>9월 회고</category>
      <category>목디스크</category>
      <category>이석증</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/442</guid>
      <comments>https://loopstudy.tistory.com/442#entry442comment</comments>
      <pubDate>Tue, 11 Oct 2022 16:34:56 +0900</pubDate>
    </item>
    <item>
      <title>뒤늦은 2022년 상반기 ~ 8월까지 회고록</title>
      <link>https://loopstudy.tistory.com/434</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이제야 작성하는 회고록...&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년까지 한 달 단위 혹은 주차 단위로 작성했다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1월 초에 &lt;a href=&quot;https://loopstudy.tistory.com/342?category=1000713&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2021년 회고&lt;/a&gt;를 작성하고나서 8개월 만에 작성하는 회고록이다. &lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;(3월에 작성하다가 코로나로 중단했었다)&amp;nbsp;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에 작성하다보니 1월부터 지금까지 시간을 어디서부터 어떻게 적을지 고민하다&amp;nbsp;그냥 손이 가는 데로 작성해본다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1월부터 지금까지... &lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 순서대로 되짚어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1~2월 - ATDD 교육으로 시작&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년 12월에 집안사정으로 진이 빠져서 1월 초까지 쉬었다가 ATDD 교육을 수강하면서 새로운 마음으로 시작하려고 했다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWTAKI/btrK1rfjPbs/gGGYhKScVQ07SvlzgfaNYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWTAKI/btrK1rfjPbs/gGGYhKScVQ07SvlzgfaNYK/img.png&quot; data-origin-width=&quot;1978&quot; data-origin-height=&quot;1820&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;48.57&quot; style=&quot;width: 48.002819734976605%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWTAKI/btrK1rfjPbs/gGGYhKScVQ07SvlzgfaNYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWTAKI%2FbtrK1rfjPbs%2FgGGYhKScVQ07SvlzgfaNYK%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;1978&quot; height=&quot;1820&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m3yYi/btrK3ZCD8tH/DivaXmkYXoagRY1SxFfdyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m3yYi/btrK3ZCD8tH/DivaXmkYXoagRY1SxFfdyK/img.png&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;1736&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;51.43&quot; style=&quot;width: 50.83438956734899%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m3yYi/btrK3ZCD8tH/DivaXmkYXoagRY1SxFfdyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm3yYi%2FbtrK3ZCD8tH%2FDivaXmkYXoagRY1SxFfdyK%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;1998&quot; height=&quot;1736&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;일일기록엔 열심히 기록했었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 내용은 따로 교육 정리에서 언급하겠다. &amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3~4월 - 드디어 올게 왔다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때까지 조심했지만 전염병 대유행은 피할 수가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3월 중에 집안에 코로나가 오면서 많은 어려움이 생겼다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rt9PI/btrK477MLgg/r3QlKjDeabdYwiTNGcAfiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rt9PI/btrK477MLgg/r3QlKjDeabdYwiTNGcAfiK/img.png&quot; data-origin-width=&quot;2014&quot; data-origin-height=&quot;1622&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;52.75&quot; style=&quot;width: 52.13365883385309%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rt9PI/btrK477MLgg/r3QlKjDeabdYwiTNGcAfiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frt9PI%2FbtrK477MLgg%2Fr3QlKjDeabdYwiTNGcAfiK%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;2014&quot; height=&quot;1622&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo6aw0/btrK1qU48Px/ha6nc6UjhwkGRJpifrzIZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo6aw0/btrK1qU48Px/ha6nc6UjhwkGRJpifrzIZK/img.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1798&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;47.25&quot; style=&quot;width: 46.703550468472486%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo6aw0/btrK1qU48Px/ha6nc6UjhwkGRJpifrzIZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo6aw0%2FbtrK1qU48Px%2Fha6nc6UjhwkGRJpifrzIZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1798&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;이전과 다르게 뭘 느꼈는지 작성도 하지 못했다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외출도 자제하고 집안에서 잠잘 때도 KF94 마스크를 끼고 있었지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가족이 차례대로 코로나로 걸리면서 집안일을 하나씩 하게 되니 제대로 집중할 수가 없었고, ATDD 마무리하는 것도 벅찼다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가족이 자가격리 풀리는 마지막 날 기준으로 일주일 더 집에 있었다. 간간히 책만 읽으면서 지냈는데 책을 제대로 읽지도 못했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다가 자가격리가 풀리고 다시 스터디 카페에 가면서, 인프라공방을 수강 신청하고 4월 말부터 인프라공방으로 다시 새로운 마음으로 시작했다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2134&quot; data-origin-height=&quot;1734&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJoglw/btrK2njoBmm/btMNypROaCwc2b1i7K1SWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJoglw/btrK2njoBmm/btMNypROaCwc2b1i7K1SWK/img.png&quot; data-alt=&quot;4월은 대부분 덧없이 흘러갔다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJoglw/btrK2njoBmm/btMNypROaCwc2b1i7K1SWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJoglw%2FbtrK2njoBmm%2FbtMNypROaCwc2b1i7K1SWK%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;2134&quot; height=&quot;1734&quot; data-origin-width=&quot;2134&quot; data-origin-height=&quot;1734&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;4월은 대부분 덧없이 흘러갔다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5월 - 인프라 공방&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인프라공방은 짧은 기간과 생소한 환경 덕분에 매일 삽질의 연속이었다. &lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;(삽질 한번에 몇 시간이 사라졌다.)&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과제 또한 많기 때문에 매일 안 하면 몰아서 하기도 힘들었다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;897&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k8Hs2/btrK2nqvb0y/vkUXnYnKL6OWcSBv8kYMf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k8Hs2/btrK2nqvb0y/vkUXnYnKL6OWcSBv8kYMf0/img.png&quot; data-alt=&quot;진행과정과 삽질을 계속 캡쳐했다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k8Hs2/btrK2nqvb0y/vkUXnYnKL6OWcSBv8kYMf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk8Hs2%2FbtrK2nqvb0y%2FvkUXnYnKL6OWcSBv8kYMf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;897&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;897&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;진행과정과 삽질을 계속 캡쳐했다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간신히 마지막까지 진행 뒤에 후기글을 작성했지만, 아직도 인프라공방에서 스쳐갔던 많은 개념을 정리하진 못했다.&lt;/p&gt;
&lt;figure id=&quot;og_1662001674535&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;'교육/인프라 공방' 카테고리의 글 목록&quot; data-og-description=&quot;오늘도 공부하자&quot; data-og-host=&quot;loopstudy.tistory.com&quot; data-og-source-url=&quot;https://loopstudy.tistory.com/category/교육/인프라%20공방&quot; data-og-url=&quot;https://loopstudy.tistory.com/category/%EA%B5%90%EC%9C%A1/%EC%9D%B8%ED%94%84%EB%9D%BC%20%EA%B3%B5%EB%B0%A9&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/KAtVW/hyPC0XBfEO/ysUK4XblGhdo4LzHImqiR0/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/KQnNd/hyPEG4dh5v/ejGOpCPzvK5cnhzykby6g1/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/thvOw/hyPDen0yrw/e9lYqjrgI0XAcSjpmQtMZK/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960&quot;&gt;&lt;a href=&quot;https://loopstudy.tistory.com/category/교육/인프라%20공방&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://loopstudy.tistory.com/category/교육/인프라%20공방&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/KAtVW/hyPC0XBfEO/ysUK4XblGhdo4LzHImqiR0/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/KQnNd/hyPEG4dh5v/ejGOpCPzvK5cnhzykby6g1/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/thvOw/hyPDen0yrw/e9lYqjrgI0XAcSjpmQtMZK/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960');&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;'교육/인프라 공방' 카테고리의 글 목록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘도 공부하자&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;loopstudy.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6월~8월 - 뭐했지???&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이쯤부터 지금하고 있는 공부는 취업도 안 하면 무의미하다는 느낌과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올초부터 추천서 써줄 테니 지원할 생각 없냐는 제안에 다시 구직을 해야겠다는 마음이 생겼다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6월 초에 스터디원이 결혼식을 하면서 커뮤니티에서 친해진 개발자 모임을 가지게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모임에서 이제 구직 준비할꺼라 말을 했지만 정신을 차려보니 벌써 6,7,8월이 지나버렸다.&lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt; (덕분에 입이직러가 되어버렸다)&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도대체 난 6,7,8월에 무엇을 한 건가...????&amp;nbsp;일일기록 흔적을 보면 매우 처참하다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nOJYp/btrK4C1ZQE7/KkMTf1ElT1fuOvoh7Jywqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nOJYp/btrK4C1ZQE7/KkMTf1ElT1fuOvoh7Jywqk/img.png&quot; data-origin-width=&quot;1680&quot; data-origin-height=&quot;1812&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;29.28&quot; style=&quot;width: 28.597967791476574%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nOJYp/btrK4C1ZQE7/KkMTf1ElT1fuOvoh7Jywqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnOJYp%2FbtrK4C1ZQE7%2FKkMTf1ElT1fuOvoh7Jywqk%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;1680&quot; height=&quot;1812&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dULrqI/btrK48sAXXv/FzqHzHDkC3ZTkk9UElMy9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dULrqI/btrK48sAXXv/FzqHzHDkC3ZTkk9UElMy9K/img.png&quot; data-origin-width=&quot;1662&quot; data-origin-height=&quot;1332&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;39.4&quot; style=&quot;width: 38.486718108561476%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dULrqI/btrK48sAXXv/FzqHzHDkC3ZTkk9UElMy9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdULrqI%2FbtrK48sAXXv%2FFzqHzHDkC3ZTkk9UElMy9K%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;1662&quot; height=&quot;1332&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxQWWM/btrK5DFN7vc/KSCTdo0I3qsgoFljMbyCW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxQWWM/btrK5DFN7vc/KSCTdo0I3qsgoFljMbyCW1/img.png&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;1692&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;31.32&quot; style=&quot;width: 30.58973270461311%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxQWWM/btrK5DFN7vc/KSCTdo0I3qsgoFljMbyCW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxQWWM%2FbtrK5DFN7vc%2FKSCTdo0I3qsgoFljMbyCW1%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;1678&quot; height=&quot;1692&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;나 뭐했니...????&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하루에 뭘 배웠는지 작성하지도 않고 손떼고 시간만 기록하는 무의미한 기록이 되어버렸고...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 무언가 책을 읽으려고 노력했고, 지난 교육을 복습하려는 흔적이 있었지만 기억에 남는 게 없다...&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;간신히 교육 후기 포스팅 몇개를 작성한 게 6,7,8월의 전부다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 보니 일일기록도 무의미해졌다는 느낌에 비공개로 전환한 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정신줄을 놓은 기분이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bebvqP/btrK4FYJQVR/4TpoKSPhIOwnBkKa5h2bWk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bebvqP/btrK4FYJQVR/4TpoKSPhIOwnBkKa5h2bWk/img.jpg&quot; data-noaft=&quot;1&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;858&quot; data-is-animation=&quot;false&quot; width=&quot;438&quot; height=&quot;516&quot; data-widthpercent=&quot;46.46&quot; style=&quot;width: 45.92306415344914%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bebvqP/btrK4FYJQVR/4TpoKSPhIOwnBkKa5h2bWk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbebvqP%2FbtrK4FYJQVR%2F4TpoKSPhIOwnBkKa5h2bWk%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;728&quot; height=&quot;858&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oBGYf/btrK4D7NjWt/1lQdUWHTduNF7H9dJQQ7DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oBGYf/btrK4D7NjWt/1lQdUWHTduNF7H9dJQQ7DK/img.png&quot; data-noaft=&quot;1&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;358&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;53.54&quot; style=&quot;width: 52.91414514887646%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oBGYf/btrK4D7NjWt/1lQdUWHTduNF7H9dJQQ7DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoBGYf%2FbtrK4D7NjWt%2F1lQdUWHTduNF7H9dJQQ7DK%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;350&quot; height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;현재 내 상태를 표현하는 짤 [웹툰-대학일기]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회고록을 작성하는 지금에서야 정상적인 정신으로 되돌아오는 느낌이다. &lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;(그동안 회고록을 안 써서 그런 건가!?)&amp;nbsp;&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;22년 지금까지 진행한 교육과 스터디&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://edu.nextstep.camp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NEXTSTEP&lt;/a&gt;에서 교육 2개와 작년부터 진행한 독서 스터디를 계속 진행했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) ATDD, 클린 코드 with Spring (1~3월)&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;figure id=&quot;og_1661773539674&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ATDD, 클린 코드 with Spring&quot; data-og-description=&quot;&quot; data-og-host=&quot;edu.nextstep.camp&quot; data-og-source-url=&quot;https://edu.nextstep.camp/c/R89PYi5H&quot; data-og-url=&quot;https://edu.nextstep.camp/c/R89PYi5H&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cGf1d4/hyPC7mNEGu/70IzTPkYcsnAIU74AtGUZ0/img.png?width=650&amp;amp;height=430&amp;amp;face=0_0_650_430,https://scrap.kakaocdn.net/dn/ffkH1/hyPBQtqNId/HEfI2jiG4gehbjlgfwTVXk/img.png?width=650&amp;amp;height=430&amp;amp;face=0_0_650_430&quot;&gt;&lt;a href=&quot;https://edu.nextstep.camp/c/R89PYi5H&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://edu.nextstep.camp/c/R89PYi5H&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cGf1d4/hyPC7mNEGu/70IzTPkYcsnAIU74AtGUZ0/img.png?width=650&amp;amp;height=430&amp;amp;face=0_0_650_430,https://scrap.kakaocdn.net/dn/ffkH1/hyPBQtqNId/HEfI2jiG4gehbjlgfwTVXk/img.png?width=650&amp;amp;height=430&amp;amp;face=0_0_650_430');&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;ATDD, 클린 코드 with Spring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;edu.nextstep.camp&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ATDD 교육은 TDD에서 한 발짝 더 나아가, 고객까지 참여하는 '인수'테스트다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ATDD를 간단히 설명하자면 다양한 관점을 가진 고객, 개발자, 테스터 등이 함께 협업하는 애자일 기법 중 하나다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같이 협업하여 서로 다른 관점을 하나로 모으고, 인수테스트를 작성하고 개발을 진행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;926&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NKe3K/btrK2m4Gdqb/DZjZROyHkiS6Cai1xkdShk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NKe3K/btrK2m4Gdqb/DZjZROyHkiS6Cai1xkdShk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NKe3K/btrK2m4Gdqb/DZjZROyHkiS6Cai1xkdShk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNKe3K%2FbtrK2m4Gdqb%2FDZjZROyHkiS6Cai1xkdShk%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;568&quot; height=&quot;480&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;926&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 개념은 &lt;a href=&quot;https://loopstudy.tistory.com/370?category=1073851&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ATDD는 무엇인가?&lt;/a&gt;로 작성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ATDD 교육은 이전 단계가 진행되었다는 가정하에 인수사항과 시나리오 등이 제공되며&amp;nbsp;Distill ~ Develop 과정을 중심으로 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Develop은 5단계로 구분되어 진행되고 인수테스트에 사용되는 도구는 &lt;a href=&quot;https://loopstudy.tistory.com/427&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RestAssured&lt;/a&gt;다. 문서화에는 Spring Rest Docs이 사용되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 상황에서 진행되는 인수테스트 교육을 통해&amp;nbsp;테스트코드 이해도도 같이 올라갔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교육에 대한 자세한 내용은 &lt;a href=&quot;https://loopstudy.tistory.com/category/교육/ATDD%2C%20클린%20코드%20with%20Spring&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;후기 포스팅&lt;/a&gt;과 &lt;a href=&quot;https://loopstudy.tistory.com/category/개발%20%26%20방법론/ATDD&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ATDD 관련 포스팅&lt;/a&gt;으로 천천히 정리하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) 인프라공방 (4~5월)&lt;/b&gt;&lt;/h4&gt;
&lt;figure id=&quot;og_1661918270909&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;인프라 공방&quot; data-og-description=&quot;&quot; data-og-host=&quot;edu.nextstep.camp&quot; data-og-source-url=&quot;https://edu.nextstep.camp/c/VI4PhjPA&quot; data-og-url=&quot;https://edu.nextstep.camp/c/VI4PhjPA&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/HiB0H/hyPC6pjLIB/LOqruR9s7Ok1MDzuInaEh1/img.jpg?width=900&amp;amp;height=600&amp;amp;face=0_0_900_600&quot;&gt;&lt;a href=&quot;https://edu.nextstep.camp/c/VI4PhjPA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://edu.nextstep.camp/c/VI4PhjPA&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/HiB0H/hyPC6pjLIB/LOqruR9s7Ok1MDzuInaEh1/img.jpg?width=900&amp;amp;height=600&amp;amp;face=0_0_900_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;인프라 공방&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;edu.nextstep.camp&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;또한 교육 기간이 끝나면 AWS 계정도 만료되기 때문에 부지런히 진행해야 한다. 끝나면 모든 게 날아가기 때문에 미리미리 정리해두는 게 필요하다. &lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;(매일 진행과정과 에러발생을 캡처해놨다)&lt;/i&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;교육은 제공된 계정으로 AWS VPC를 구성하고 네트워크 과정을 이해하면서 나만의 도메인에 웹을 띄우는 걸로 시작된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생소한 환경 덕분에 시작부터 삽질을 시작해서 마지막 날까지 삽질의 연속이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스쳐가는 개념과 도구, 분량은 다른 교육에 비해 최소 3,4배는 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교육에 대한 자세한 내용과 후기는 &lt;a href=&quot;https://loopstudy.tistory.com/category/교육/인프라%20공방&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인프라 공방 카테고리&lt;/a&gt;에 주차별로 정리했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tNBji/btrK4D6fwjO/TCsFHWIgoIqAj9KvmQGzDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tNBji/btrK4D6fwjO/TCsFHWIgoIqAj9KvmQGzDK/img.png&quot; data-alt=&quot;인프라에는 다양한게 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tNBji/btrK4D6fwjO/TCsFHWIgoIqAj9KvmQGzDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtNBji%2FbtrK4D6fwjO%2FTCsFHWIgoIqAj9KvmQGzDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;728&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;728&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3) 삼색펜 스터디&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년 그대로 계속 이어져온 스터디로 이제 일 년 반이 되어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;22년도에 스터디로 읽어온 책은&amp;nbsp;&lt;i&gt;대규모 서비스를 지탱하는 기술, 데이터 중심 애플리케이션 설계, 클린 코드, 이펙티브 자바&lt;/i&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 삼색펜 스터디는 메인과 서브 2개로 진행중이다.&amp;nbsp;&lt;/p&gt;
&lt;p 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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;책 읽기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년에 이어서 책은 꾸준히 읽고 있지 작년에 비해 많이 읽지는 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 목록은 시간 순서대로 읽었던 책 내역이다. 챕터 3개 이상 읽은 내용만 모았고 작년에 읽었던 책도 있다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;대규모 서비스를 지탱하는 기술&lt;/li&gt;
&lt;li&gt;린 애자일 기법을 활용한 테스트 주도 개발&lt;/li&gt;
&lt;li&gt;만들면서 배우는 클린 아키텍처&amp;nbsp;&lt;/li&gt;
&lt;li&gt;스프링 인 액션&lt;/li&gt;
&lt;li&gt;모던 자바 인 액션&lt;/li&gt;
&lt;li&gt;데이터 중심 애플리케이션 설계&lt;/li&gt;
&lt;li&gt;이펙티브 자바&lt;/li&gt;
&lt;li&gt;클린 소프트웨어&lt;/li&gt;
&lt;li&gt;클린 코드&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외 살짝 본 내역이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;SQL 레벨업&lt;/li&gt;
&lt;li&gt;클린 애자일&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어려워서 제대로 이해하지 못한 책도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 일명 멧돼지라 불리는 '데이터 중심 애플리케이션 설계'다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해할 수 있는 챕터는 이해할 순 있지만, 그 외에는 대략 개념만 느끼고? 지나갔다. &lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;('엔터프라이즈 애플리케이션 아키텍처 패턴'과 비슷하다)&amp;nbsp;&lt;/i&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;린 애자일 기법을 활용한 테스트 주도 개발은 애자일 기법인 ATDD를 주제로 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비디오 대여점을 사례로 소설처럼 서술되는데 ATDD에 대한 개념을 잡기엔 좋았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습하면서 ATDD에 대해 알고 싶으면 NEXTSTEP의 ATDD 교육을 추천한다.&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;이 책이 집필된 배경은 09년 일본의 하테나라는 서비스를 사례로 진행된 걸로 기억난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하테나 초기엔 트래픽이 적어서 어떻게든 야메로 유지보수가 되었는데, 야매로는 감당할 수 없는 트래픽이 오자 기초지식의 중요성이 대두된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 읽었지만, 중반 내용은 그다지 별로였다. 데이터 압축, 알고리즘 등 검색엔진에 대한 과제 내용으로 이해하기 힘들었고 perl로 된 예제만 나와서 정독하진 않았다.&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;모던 자바 인 액션은 초반까지 읽었다가 중단된 상태인데, 자바8에서 대격변?이 생긴 이유와 람다, 스트림 등이 어떤 방식으로 작동하고 사용되는지에 한번 찍먹만 한 상태다.&amp;nbsp;조만간 처음부터 읽으면서 정리해야겠다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외의 책들도 제목만 보면 유명해서 읽어본 사람이라면 어떤 내용인지 알 것이다.&lt;/p&gt;
&lt;p 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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;간단히 평가하자면&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 뭔가 정신줄 놓은 듯이 시간만 하염없이 보낸 기분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상반기에 진행했던 ATDD, 인프라공방과 책도 정리를 안 하고 읽기만 해서 스쳐가듯이 살짝 남은 거밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 여름의 더위가 가고 밤에 쌀쌀해지는 지금에서야 놓쳤던 정신줄을 잡은 느낌이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blEC0P/btrK553T4fJ/M4yIGGHAw7SpLrk0ynWpsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blEC0P/btrK553T4fJ/M4yIGGHAw7SpLrk0ynWpsk/img.png&quot; data-alt=&quot;언제 정신줄을 놓은걸까 [웹툰-놓지마정신줄]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blEC0P/btrK553T4fJ/M4yIGGHAw7SpLrk0ynWpsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblEC0P%2FbtrK553T4fJ%2FM4yIGGHAw7SpLrk0ynWpsk%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;250&quot; height=&quot;179&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;언제 정신줄을 놓은걸까 [웹툰-놓지마정신줄]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;남은 22년 목표&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 이 상태를 계속 유지할 수 없기도 하고 타이밍 좋게&amp;nbsp;작년에 중단되었던 NEXTSTEP 멘토링을 다시 신청할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토링은 이력서 피드백 &amp;amp; 모의 면접 등을 진행하게 되는데, 지금 상태를 가장 잘 파악해주는 좋은 기회가 아닌가 싶다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 멘토링을 진행하면서 자바와 스프링을 다시 학습하고 정리할 예정이다.&amp;nbsp;그간 객체지향에 집중했다 보니 소홀했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 책을 읽고 배우는 것도 좋지만 정리할 타이밍을 놓쳐서&amp;nbsp;스쳐 지나간 많은 개념을 정리해야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 정신줄 놓은 걸 만회하는 시간으로 가져야겠다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;i&gt;&lt;b&gt;끝.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;</description>
      <category>목표 및 회고</category>
      <category>1 ~ 8월까지 회고록</category>
      <category>22년 회고록</category>
      <category>ATDD</category>
      <category>상반기 회고록</category>
      <category>인프라 공방</category>
      <category>회고록</category>
      <author>loop-study</author>
      <guid isPermaLink="true">https://loopstudy.tistory.com/434</guid>
      <comments>https://loopstudy.tistory.com/434#entry434comment</comments>
      <pubDate>Thu, 1 Sep 2022 15:25:18 +0900</pubDate>
    </item>
  </channel>
</rss>