<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[RSS Feed of hoon.blog]]></title><description><![CDATA[꾸준히, 의미있는 학습을 기록하기 위한 공간입니다.]]></description><link>https://hoonblog.netlify.app</link><generator>GatsbyJS</generator><lastBuildDate>Fri, 24 Jan 2025 09:52:58 GMT</lastBuildDate><item><title><![CDATA[[QueryDSL] QueryDSL 사용 시 NPE가 발생했을 때 해결하기]]></title><description><![CDATA[들어가며 프로젝트를 진행하면서 동적 쿼리를 작성할 일이 많아 QueryDSL을 도입하면서 발생했던 NullPointerException 오류를 해결하면서 배웠던 내용을 정리하고자 작성하게 되었다.  도메인 구조  하나의 피드 본문(FeedContent…]]></description><link>https://hoonblog.netlify.app/npe-occurs-when-using-querydsl/</link><guid isPermaLink="false">https://hoonblog.netlify.app/npe-occurs-when-using-querydsl/</guid><pubDate>Sat, 20 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;프로젝트를 진행하면서 동적 쿼리를 작성할 일이 많아 QueryDSL을 도입하면서 발생했던 NullPointerException 오류를 해결하면서 배웠던 내용을 정리하고자 작성하게 되었다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/eb0a67f5ca81541a0e6b5da18552b9db/bab36/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 8.823529411764705%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAYUlEQVR42j2MWw6AIAwEOYpBoeWpQeD+N1tbMX5MZrdN1hQXkAR19REnJbRQlg9G2wm3eMpfe/+y3lYPL9oVM7ng4owmDBlSeqzv+KCKXm9kGXDbjmC9QCDr/sxi/hytxwO9Vjt5vgJRRAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/eb0a67f5ca81541a0e6b5da18552b9db/ca1dc/1.png&apos; srcset=&apos;/static/eb0a67f5ca81541a0e6b5da18552b9db/e7570/1.png 170w,
/static/eb0a67f5ca81541a0e6b5da18552b9db/f46e7/1.png 340w,
/static/eb0a67f5ca81541a0e6b5da18552b9db/ca1dc/1.png 680w,
/static/eb0a67f5ca81541a0e6b5da18552b9db/02d09/1.png 1020w,
/static/eb0a67f5ca81541a0e6b5da18552b9db/9d567/1.png 1360w,
/static/eb0a67f5ca81541a0e6b5da18552b9db/bab36/1.png 1906w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;java.lang.NullPointerException: Cannot read field &quot;id&quot; because &quot;sidepair.domain.project.QProjectMember.projectMember.project.feedContent.feed&quot; is null&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;[도메인 구조]&lt;/h2&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7353724c49117cfea72597d70c754f2f/e7c3c/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 58.82352941176471%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABf0lEQVR42p1SPQ/BUBRtfSVIMCAsXUQimJj4DU0NFonEYGg6VPwEsUmL+AFGi4nYmkjM1b/AYjSJ2HwceTd5YlARLzl5r+f1nnvvuU8QRRGCICCXy0FRFEKxWCSOIZPJQJZl4kul0ov/AgHJZBLH4xG32w33+x2n0wntdhvNZhP7/R5sMe56vaJcLlOgx+NxFwwEAphOp9hut3AcB7PZDJIkIZFIYDKZwLZtbDYbrFYrSs4FfT7fC7xT4YcWKGE0GqUzC3wL/lwh//H9zL/r9TpM08R4PEa320U4HCa+Wq1iNBphOByi3+8jlUq5V8jFWPButyNvz+czHo8HDYjdLRYL8vZyudCuadr3lrlorVajCgeDAXRdRygUIr5SqVB1hmGg1+shnU7/7qEb/H4/YrHYZw/dwKbp9Xpf4M+l0WhgvV7Dsiwsl0sUCoX/KuSC8/mcvDscDrSrqvqfIPc2n8/TIDqdDlqtFr3Zvz1k3gWDQcTjcWSzWUQiERoWS/YEi+NpxkWWTwoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/7353724c49117cfea72597d70c754f2f/ca1dc/2.png&apos; srcset=&apos;/static/7353724c49117cfea72597d70c754f2f/e7570/2.png 170w,
/static/7353724c49117cfea72597d70c754f2f/f46e7/2.png 340w,
/static/7353724c49117cfea72597d70c754f2f/ca1dc/2.png 680w,
/static/7353724c49117cfea72597d70c754f2f/02d09/2.png 1020w,
/static/7353724c49117cfea72597d70c754f2f/9d567/2.png 1360w,
/static/7353724c49117cfea72597d70c754f2f/e7c3c/2.png 1448w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;하나의 피드 본문(FeedContent) 정보에 대해서 하나의 프로젝트(Project)가 생성될 수 있고, 하나의 프로젝트에 대해서 여러 개의 프로젝트 대기 멤버(ProjectPendingMembers)가 생길 수 있다는 것이다.&lt;/p&gt;
&lt;p&gt;위 문제를 발견하게 된 테스트 코드는 아래와 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 카테고리_조건_없이_주어진_피드_이전의_데이터를_참가중인_인원이_많은순으로_조회한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt; serviceFeed1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 노드_정보를_포함한_피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;서비스 피드&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; creator&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; serviceCategory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt; serviceFeed2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 노드_정보를_포함한_피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;서비스 피드2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; creator&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; serviceCategory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt; commerceFeed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 노드_정보를_포함한_피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;이커머스 피드&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; creator&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; commerceCategory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt; serviceFeed1Project &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 프로젝트를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serviceFeed1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; creator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt; serviceFeed2Project &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 프로젝트를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serviceFeed2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; creator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt; commerceFeedProject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 프로젝트를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;commerceFeed&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; creator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// serviceFeed1 : 참가인원 0명&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// serviceFeed2 : 참가인원 1명&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ProjectMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; serviceFeed2ProjectMembers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProjectMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ProjectRole&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LEADER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LocalDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; serviceFeed2Project&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; creator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    projectMemberRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;saveAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serviceFeed2ProjectMembers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// commerceFeed : 참가인원 2명&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ProjectMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; commerceFeedProjectMembers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProjectMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ProjectRole&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LEADER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LocalDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; commerceFeedProject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; creator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProjectMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ProjectRole&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;FOLLOWER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LocalDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; commerceFeedProject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; follower&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    projectMemberRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;saveAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;commerceFeedProjectMembers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; category &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedOrderType&lt;/span&gt; orderType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedOrderType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PARTICIPANT_COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// when&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; firstFeedRequest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; feedRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findFeedsByCategory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;category&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; orderType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; secondFeedRequest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; feedRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findFeedsByCategory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;category&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; orderType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            serviceFeed2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;코드가 상당히 복잡하지만 별거없다. 그냥 피드를 생성하고, 피드에 대한 참가인원을 추가하는 코드이다.
해당 코드는 아래와 같이 구현이 되어 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findFeedsByCategory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedOrderType&lt;/span&gt; orderType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                            &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; lastId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; pageSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;selectFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;feed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;lessThanLastId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lastId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; orderType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
           	&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BooleanExpression&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lessThanLastId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; lastId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedOrderType&lt;/span&gt; orderType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NumberPath&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; projectMemberFeedId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; projectMember&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feedContent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feed&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;participantCountCond&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;projectMemberFeedId&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;feed&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;participantCountCond&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;projectMemberFeedId&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lastId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;인자로 받은 lastId (현재는 피드의 PK 값이 들어오고 있다.)에 해당하는 피드의 참여자 수보다 더 적은 참여자 수를 구하는 피드를 구하는 쿼리이다. &lt;/p&gt;
&lt;h2&gt;[NPE가 발생할 지점을 찾아보기]&lt;/h2&gt;
&lt;p&gt;처음에 이 오류를 접했을 때는 아래와 같은 예외 메시지 중에서 단순하게 이 부분에만 집중을 했었다.
sidepair.domain.project.QProjectMember.projectMember.project.feedContent.feed is null&lt;/p&gt;
&lt;p&gt;그래서 projectMember를 저장한 후에 피드에 대한 정보가 제대로 저장이 안 되어 있나 싶어서 findAll로 찾아보았다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ProjectMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; projectMembers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; projectMemberRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;projectMembers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getProject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFeedContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFeed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNotNull&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;projectMembers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getProject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFeedContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFeed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNotNull&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;projectMembers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getProject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFeedContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFeed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNotNull&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;NPE니까 당연히 feed의 id 값이 Null이 되어서 테스트가 실패하겠지?라고 생각하였다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5d9b53bc112a720b56ab4e2ae8efc3ca/b79fc/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 31.176470588235293%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABGklEQVR42nWQ207CQBRF+x1ybQ2UTqdzZtoO9AYFG4RqUBN9UiP//xXbQwkviA8rk0zO7LP2OEW5As1XyNbPKB9esNq+ouIzqw8omjfkfG+rFvNlC7IbiCiBkIqhmzhkCKldIDKWhzUWeQZtEgTKQtkKpAlkUlC8gNIWEcUdUhmEPH+NY2KLumnwdHjHcr1FVm4g9RySEiS2hI5TFLwkL+suRISqezgLJKa++IMjbYuo+kCx+8Jyf0TdHlE8fiNrPlHufiDtHt69z9YpBkMXd70hev0R+oPxTZyzqunqCnlR5zpsI7naTEgMR273P6RTRHx/Mhm7E7jelJedcb1JBwcS/kMqDT8IOdBDyIEny1PlQETwZyEjrwjxCwNFuvbezKnmAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/5d9b53bc112a720b56ab4e2ae8efc3ca/ca1dc/3.png&apos; srcset=&apos;/static/5d9b53bc112a720b56ab4e2ae8efc3ca/e7570/3.png 170w,
/static/5d9b53bc112a720b56ab4e2ae8efc3ca/f46e7/3.png 340w,
/static/5d9b53bc112a720b56ab4e2ae8efc3ca/ca1dc/3.png 680w,
/static/5d9b53bc112a720b56ab4e2ae8efc3ca/02d09/3.png 1020w,
/static/5d9b53bc112a720b56ab4e2ae8efc3ca/9d567/3.png 1360w,
/static/5d9b53bc112a720b56ab4e2ae8efc3ca/b79fc/3.png 1538w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;하지만 테스트가 놀랍게도 성공한 것을 볼 수 있었다. 그래서 값 자체는 제대로 들어갔겠구나 싶어서 다른 방향을 탐색해보았다.&lt;/p&gt;
&lt;h2&gt;[QueryDSL의 객체 그래프]&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NumberPath&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; projectMemberFeedId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; projectMember&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feedContent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feed&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;문제가 발생했던 라인은 정확하게 위 라인이었다.
어떠한 값이 들어가고 말고의 문제를 떠나서, 객체 그래프를 탐색할 때 뭔가 문제가 있을 것 같다는 생각이 들었다.
그래서 열심히 구글링을 해본 결과, 아래와 같은 글을 발견하게 되었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/48380798/nullpointerexception-on-querydsl-where-clause&quot;&gt;NullPointerException on QueryDSL where clause&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그리고 답변 내용에서 말해 주신 &lt;code class=&quot;language-text&quot;&gt;공식 문서&lt;/code&gt;를 한 번 읽어보았다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By default Querydsl initializes only reference properties of the first two levels.
In cases where longer initialization paths are required, these have to be annotated in the domain types via
com.mysema.query.annotations.QueryInit annotations.
QueryInit is used on properties where deep initializations are needed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;기본적으로 QueryDSL은 초기 2단계의 레벨에 있는 프로퍼티만 초기화하게 된다.
만약 그 이상의 path를 초기화하고 싶다면 &lt;code class=&quot;language-text&quot;&gt;@QueryInit&lt;/code&gt; 어노테이션을 통해서 직접 지정해줄 수 있다.
한 번 우리의 문제 상황에 적용해보자.&lt;/p&gt;
&lt;h2&gt;@QueryInit&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;@QueryInit&lt;/code&gt;의 경우 기본적으로 @Entity 어노테이션이 붙어 있는 클래스의 필드에 대해서 적용이 가능하다.
내부 인자로 초기화하고 싶은 path를 지정해줄 수 있으며, *을 통해 와일드카드를 통해서도 지정이 가능하다.&lt;/p&gt;
&lt;p&gt;먼저, &lt;code class=&quot;language-text&quot;&gt;@QueryInit&lt;/code&gt;을 지정하지 않았을 때의 큐파일을 디버깅해보았다. (QProject)&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f946573b6cee6be4c9dc0c2a6dd62f50/bab36/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 54.70588235294118%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB1ElEQVR42m1T7XKbMBDkcWpjMAj0jTDggBPHbZKZ9v0fZbun2p0m0x87J510e3srKGy6wKUNgdHf15aoGovycMSurLE/3FHewfzf3BcULi7ww4RgArT2UHbCuP0k8QrjEtqeOcn3LkfZ18rgSDSCzn5Ccb2943r7wLJe4eJE8hnDaYMLEwwJvE/o3ZDJE9cnYpQ9BSiSN537QyxNWoNinBbE4QQfEy+wi+pxqBqUdYtBa5yTh7Ee2kYMvBdDgrUBvXFUqbGrFL7tqwyxopiWlWoSCzysi5m0FEJCW8tGZ3RuQU9CUVE1HZX0sH7IdQIfxxyro0Ih6nRWQA+Nzw8hnXbseGTuvK6IPuaxRWWg3/P5gufrD1r1hpfXN66/4/Jyo2pPhfMT0kjf0sSuHJvGqs7kbkpb/NpmvDoDxfEa5vPovB95X5QFChK1QtbyvLAxwg0DP5kEE+iNc9BezO7RaofbuuDJB45JQpJ+HVUIhUwEiBVFYzsIlNdoCYkqGNS9QkPCdVsRXEBnQi4UlUIihB3PBWKXof+CYl/Ss/9gt6vQkmC7rPDOk9DnB5Pix5iylih5eWX5CYrHi35C3eSvvqKaeZkx0RZRImcyWs2X/heSe9T+BnRMZ8zAO/+sAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;4&apos; title=&apos;&apos; src=&apos;/static/f946573b6cee6be4c9dc0c2a6dd62f50/ca1dc/4.png&apos; srcset=&apos;/static/f946573b6cee6be4c9dc0c2a6dd62f50/e7570/4.png 170w,
/static/f946573b6cee6be4c9dc0c2a6dd62f50/f46e7/4.png 340w,
/static/f946573b6cee6be4c9dc0c2a6dd62f50/ca1dc/4.png 680w,
/static/f946573b6cee6be4c9dc0c2a6dd62f50/02d09/4.png 1020w,
/static/f946573b6cee6be4c9dc0c2a6dd62f50/9d567/4.png 1360w,
/static/f946573b6cee6be4c9dc0c2a6dd62f50/bab36/4.png 1906w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;QProject -&gt; QFeedContents -&gt; QFeed(null)&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;p&gt;확인해보면 Project에서 QFeedContent까지의 값은 잘 가져오지만, QFeed에 대해서는 정의가 되어 있지 않은 것을 볼 수 있다. 여기서 QFeed 값이 null로 정의되었기 때문에 탐색이 불가능했던 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProjectMember&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

   &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@ManyToOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fetch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FetchType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LAZY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@JoinColumn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;project_id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nullable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@QueryInit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;feedContent.feed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt; project&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그래서, 위와 같이 ProjectMember 엔티티가 Project 엔티티를 정의한 필드에 &lt;code class=&quot;language-text&quot;&gt;@QueryInit&lt;/code&gt;을 정의해주었다.
이렇게 되면 QProject이 초기화될 때 FeedContent와 Feed 정보까지 함께 초기화가 가능할 것이다.
참고로, 내부 value의 값은 project 엔티티가 참조하고 있는 실제 필드명으로 작성해야 한다.&lt;/p&gt;
&lt;p&gt;이런 식으로 잘못된 필드 값을 입력하게 되면 컴파일 타임 때 오류가 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/22414c78314bc4d48ec6eef6d1c9bede/5fdae/5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 26.47058823529412%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAtUlEQVR42nWQWQ6DMAxEc48CISxJ7BAoHy3qQu9/q6nDIiHUfjxNxp5ItlVjA3RlUZQ1uuAxREYcRgQe4FpGpivkJ4oD+UkVhQjPAnULRBEsPvCqZ2jLplwi5Ug8b3U1yhSzj/hQj4fo03eYJXh3QXyHKeHW2lv66X21hJdfMzfZcBJN/0fLUM406GsHlrXJtOhFrdTS+KWgt1X0wSc1ul50z+09lRUGFyHbWN6nu/y61797fgG5CY/wEmfuLgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;5&apos; title=&apos;&apos; src=&apos;/static/22414c78314bc4d48ec6eef6d1c9bede/ca1dc/5.png&apos; srcset=&apos;/static/22414c78314bc4d48ec6eef6d1c9bede/e7570/5.png 170w,
/static/22414c78314bc4d48ec6eef6d1c9bede/f46e7/5.png 340w,
/static/22414c78314bc4d48ec6eef6d1c9bede/ca1dc/5.png 680w,
/static/22414c78314bc4d48ec6eef6d1c9bede/02d09/5.png 1020w,
/static/22414c78314bc4d48ec6eef6d1c9bede/9d567/5.png 1360w,
/static/22414c78314bc4d48ec6eef6d1c9bede/5fdae/5.png 1788w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;project가 실제로 의존하고 있는 필드명으로 작성해야 한다.&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@ManyToOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fetch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FetchType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LAZY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@JoinColumn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;project_id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nullable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@QueryInit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;feedContent.*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt; project&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;추가적으로, 이렇게 와일드카드로 명시해도 잘 동작한다.&lt;/h4&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/038ea924fbfa0cd603081462fe25ba2c/30d26/6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 41.76470588235294%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAABhUlEQVR42l2RWZKcMBBEuc64F2gtgJYWILFN054Jf8w4fP+DpFPyEmF/ZAgk1ausVCX6Ea2dIU2CorSNMG6Bsgv64Ylajzhfb3g5Xf/VOavGl/9UbfOBaVoxrQ+k5QHnBtj+TnjAuH5DWN7ZgE2590ddVuehtMVN9kVCG8oS+HjD6/GO7fUN6/4Vy/b8C+h6D52le4zec89BExTYNPoRkwswhs07h1oYXGqJyocJw5Tg7gN64wjJXVseCpwuTRlLCoU5eHS/i3VnIVuDRmgI1Zb1TNjpwpHvQ8SUFsR5JTQ7syxkEQtydjmXRrcwwwxtIhSdSzoWqudqkOvjspfafL8Ax7ggjOkXqDNo6eDayAJ7OV1Qyw7zkhCd4bnjuWMsAWneGNUT235wyhn1TaEKGcifLB9GWM9H4WWpuzJKBkuO9REDjlZhb1scpsdnivixrvg+JwyC8dDdmRFV2ar1objq7b0ohy9UV6A3Qht+JwIma/i6jIRxON5b6HDfHohppeOhOPwJbSwLh1KGb7YAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;6&apos; title=&apos;&apos; src=&apos;/static/038ea924fbfa0cd603081462fe25ba2c/ca1dc/6.png&apos; srcset=&apos;/static/038ea924fbfa0cd603081462fe25ba2c/e7570/6.png 170w,
/static/038ea924fbfa0cd603081462fe25ba2c/f46e7/6.png 340w,
/static/038ea924fbfa0cd603081462fe25ba2c/ca1dc/6.png 680w,
/static/038ea924fbfa0cd603081462fe25ba2c/02d09/6.png 1020w,
/static/038ea924fbfa0cd603081462fe25ba2c/9d567/6.png 1360w,
/static/038ea924fbfa0cd603081462fe25ba2c/30d26/6.png 1894w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;QProject -&gt; QFeedContents -&gt; QFeed&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;p&gt;수정 후에 다시 디버깅을 진행해보면 이번에는 feed에 대한 정보도 잘 채워진 것을 확인할 수 있다&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f7b774f01623d40c82ce376ef1797649/8ef96/7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 24.11764705882353%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA1klEQVR42o2PwW6DMBBE/SNNChRDbGxjbIzbQBqkQiJVkdJI/P+nTLeohx5StYen2Tns7CzT/hnxMGEYzxiOJ5pPq+/6GWE/wfgDhLIQlYFU9Z+wfloQxgX+9Qa3v0DEK/kbfBvQxh6m6aBrRzT/CmXxOGF+XzDOH4jDGe3LG1w3QlYajWspOK6BvJQohUKWl0jSHEnG78J2slqXlTbQxhI1hFTghYR1AR21tE1AUVZ4orCUlh42ya+wn3W/XhLfygtBRyy1DKitX33Od8hJt48ZNtv0Lp8TVZomdunIKwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;7&apos; title=&apos;&apos; src=&apos;/static/f7b774f01623d40c82ce376ef1797649/ca1dc/7.png&apos; srcset=&apos;/static/f7b774f01623d40c82ce376ef1797649/e7570/7.png 170w,
/static/f7b774f01623d40c82ce376ef1797649/f46e7/7.png 340w,
/static/f7b774f01623d40c82ce376ef1797649/ca1dc/7.png 680w,
/static/f7b774f01623d40c82ce376ef1797649/02d09/7.png 1020w,
/static/f7b774f01623d40c82ce376ef1797649/9d567/7.png 1360w,
/static/f7b774f01623d40c82ce376ef1797649/8ef96/7.png 1960w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;테스트도 정상적으로 통과한다.&lt;/p&gt;
&lt;p&gt;+) 추가적으로, 이렇게 &lt;code class=&quot;language-text&quot;&gt;@QueryInit&lt;/code&gt;을 특정 필드에 적용하고 나면 기존에 잘 돌아가던 쿼리들이 안 돌아갈 수도 있다.
나 같은 경우에는 비슷한 다른 쿼리에서 오류가 발생했었는데, 2단계 레벨에 있는 필드에 대해서 NPE가 발생했었다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0f5b6db3bb4a5f036ca6db58680a5d2a/8ef96/8.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 9.411764705882353%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAbUlEQVR42jWNQQ7CMAwE+xGE0jbGTtwmJOUA///XsqTlMBqvtLanjyS8BhnPaPBV4cOGbXmgkDzLmP95Y97pShr7P9fL0zsmNHVUcxQ96bmgpB2djzqLB48f10IXR8sVtgg0RNgcIWGF0rd7wBee2js6Tk74xQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;8&apos; title=&apos;&apos; src=&apos;/static/0f5b6db3bb4a5f036ca6db58680a5d2a/ca1dc/8.png&apos; srcset=&apos;/static/0f5b6db3bb4a5f036ca6db58680a5d2a/e7570/8.png 170w,
/static/0f5b6db3bb4a5f036ca6db58680a5d2a/f46e7/8.png 340w,
/static/0f5b6db3bb4a5f036ca6db58680a5d2a/ca1dc/8.png 680w,
/static/0f5b6db3bb4a5f036ca6db58680a5d2a/02d09/8.png 1020w,
/static/0f5b6db3bb4a5f036ca6db58680a5d2a/9d567/8.png 1360w,
/static/0f5b6db3bb4a5f036ca6db58680a5d2a/8ef96/8.png 1960w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;비슷한 오류지만 projectMember -&gt; member -&gt; email (VO여서 단계에 반영하지 않는 것 같다. 공식문서에서 명시 되어 있듯이 3단계는 반영되지 않는것 같다.)에 대해서 오류가 발생한 것이었다.
&lt;code class=&quot;language-text&quot;&gt;@QueryInit&lt;/code&gt;을 달지 않았을 때는 3단계까지 잘 갔었는데, 명시적으로 어노테이션을 지정해주니까 이렇게 된 것 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@ManyToOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fetch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FetchType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LAZY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@JoinColumn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;project_id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nullable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@QueryInit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;feedContent.feed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt; project&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@ManyToOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fetch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FetchType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LAZY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@JoinColumn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;member_id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nullable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@QueryInit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Member&lt;/span&gt; member&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그래서 member 필드에 대해서는 이렇게 email에 대해서도 정의를 해주었다.&lt;/p&gt;
&lt;h2&gt;[정리]&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;@QueryInit&lt;/code&gt; 어노테이션을 직접 사용해보니 더 자세히 알게 된 것 같다.
사실 해결 방법은 아주 간단했는데 처음 마주한 오류여서 해결하는 데 시간이 오래 걸렸다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[Spring] @SpringBootTest에서 지연 로딩 사용하기 - no Session 방지하기]]></title><description><![CDATA[들어가며 이번 프로젝트에서 E2E 테스트 환경을 구축하기 위해서 @SpringBootTest를 통해 테스트 코드를 작성하고 있는데, 아래와 같은 오류를 만나게 되었다. failed to lazily initialize a collection of…]]></description><link>https://hoonblog.netlify.app/using-delayed-loading-in-test/</link><guid isPermaLink="false">https://hoonblog.netlify.app/using-delayed-loading-in-test/</guid><pubDate>Mon, 15 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;이번 프로젝트에서 E2E 테스트 환경을 구축하기 위해서 @SpringBootTest를 통해 테스트 코드를 작성하고 있는데, 아래와 같은 오류를 만나게 되었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;failed to lazily initialize a collection of role:  sidepair.domain.feed.FeedContent.nodes.values: could not initialize proxy - no Session&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;상황은 아래와 같다. (추후 코드로 더 잘 살펴볼 예정이다.)
A라는 생성 API와 B라는 조회 API가 있을 때, 팀 내에서 기능을 세분화한 다음 각자 개발을 진행하다 보니 B를 개발하는 시점에 A라는 API가 없어, 통합 테스트 때 repository를 의존하여 직접 save를 하게 되었다.&lt;/p&gt;
&lt;p&gt;하지만, save 후 반환된 엔티티의 객체를 조회할 때 지연 로딩을 사용하다 보니 트랜잭션이 필요하게 되었는데, 테스트 메서드에서는 repository를 호출하는 시점에서만 트랜잭션이 걸리고, 해당 객체를 사용하는 시점에는 트랜잭션이 없어 영속성 컨텍스트가 없는 상태가 된 것이다. 그러다 보니 세션 정보가 없어 지연 로딩을 사용할 수 없다는 오류가 발생하게 되었다.&lt;/p&gt;
&lt;p&gt;당시 이 오류를 처음 접했을 때는 테스트 메서드의 트랜잭션이 없어서 발생한 문제니까, A api가 merge 된 이후에 작업하셔도 충분할 것 같았지만, 곰곰이 생각해보니 이게 과연 옳은 해답인가? 라는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;앞으로도 이런 테스트 상황이 생길 텐데, 그럴 때마다 이럴 수는 없기 때문에 이번에 공부하면서 새로운 방법을 적용하게 되었다.&lt;/p&gt;
&lt;h2&gt;[엔티티 소개]&lt;/h2&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5cc308fb9a2614f20dc7d1d534f68eaf/248ed/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 48.23529411764706%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABdklEQVR42oWSzcpBURSGDwolhQH5yc8EuQZlxCWYugAzMVB+Ji7A0IikjMmMKJKLMJIkuQAkenx71zmd0+c7367VWrt373e/611bsVgsKIoiQ9T6vdvtJpFIkEwmicfjuFwuDTMJI5GarVarzH6/n0wmg8/nM+B/xmg0Yr1es1wuWa1WFAoFHA4HoVCIbrfLZrNhOp3KXCwWDY99DX7W8/nkfr+LktlsRqlUolar8Xg8eL/fHI9Hic3n8/9VNptNhMp+v0+v1yOVSmmXyuUy4/GY4XDIYDAgm80avLbZbFroHjE3WbTv9XoNRKYKhR/qIVHr/cnn87RaLdrtNpVKRU5bJU6n09KWarVKvV4nl8t9V6gSRqNR6evtduN8PksPxeACgQAej0cOUKzT6cTr9eJ6vRIMBn8Tqu2IP7dYLNjv9+x2O0naaDS0c51Oh8vlwna75XA4MJlMcDqd5h4K/yKRCLFYTP5HvXeiE6FWYOFwGLvdLrEPGgVK2VbH54UAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/5cc308fb9a2614f20dc7d1d534f68eaf/ca1dc/2.png&apos; srcset=&apos;/static/5cc308fb9a2614f20dc7d1d534f68eaf/e7570/2.png 170w,
/static/5cc308fb9a2614f20dc7d1d534f68eaf/f46e7/2.png 340w,
/static/5cc308fb9a2614f20dc7d1d534f68eaf/ca1dc/2.png 680w,
/static/5cc308fb9a2614f20dc7d1d534f68eaf/02d09/2.png 1020w,
/static/5cc308fb9a2614f20dc7d1d534f68eaf/248ed/2.png 1268w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;현 문제 상황에서 필요한 간단한 엔티티 다이어그램이다.
피드 (Feed)는 피드 내용들(FeedContents)에 대해서 1:N 관계를 맺고 있으며, 각 피드 내용(FeedContent)은 피드 노드들(FeedNodes)에 대해서 또 다시 1:N 관계를 가지고 있다.&lt;/p&gt;
&lt;p&gt;이를 코드로 봤을 때는 대략적으로 아래와 같이 구성된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Entity&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;access &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AccessLevel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PROTECTED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BaseCreatedTimeEntity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Embedded&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContents&lt;/span&gt; contents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Entity&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;access &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AccessLevel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PROTECTED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@Getter&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BaseUpdatedTimeEntity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Embedded&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedNodes&lt;/span&gt; nodes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

   &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedNodes&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; nodes&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Embeddable&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;access &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AccessLevel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PROTECTED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedNodes&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@OneToMany&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fetch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FetchType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LAZY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cascade &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CascadeType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PERSIST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CascadeType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MERGE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mappedBy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;feedContent&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; values &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;여기서 봐야하는 점은, 피드(Feed) - 피드 본문(FeedContent)과 피드 본문(FeedContent)과 피드 노드(FeedNode) 모두가 LAZY 전략을 사용하고 있다는 것이다.&lt;/p&gt;
&lt;h2&gt;[문제 상황]&lt;/h2&gt;
&lt;p&gt;아래의 테스트 코드는 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)을 통해서 통합 테스트 환경을 구축한 상태에서 진행된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 테스트&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonProcessingException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 제목&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 소개글&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 본문&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드_본문 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Here!&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt; 피드 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; feedRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; feedContentRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findFirstByFeedOrderByCreatedAtDesc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;코드의 첫 라인을 보면 &lt;code class=&quot;language-text&quot;&gt;피드를_생성한다();&lt;/code&gt; 메서드를 통해 피드 아이디를 반환받고 있다. 여기서는 실제 API call을 진행하고 있기 때문에 실제로 생성된 피드의 아이디만을 반환받는다.
반환받은 아이디를 바탕으로 피드 엔티티를 얻어오기 위해 &lt;code class=&quot;language-text&quot;&gt;findById()&lt;/code&gt;를 통해 피드 엔티티를 조회해오며,
여기서 가장 최근에 생성된 피드 본문 엔티티를 가져오기 위해 한 번 더 조회를 진행한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;물론, 피드 엔티티로부터 가장 최근의 피드 본문을 받아오는 방법도 있겠지만, 현 프로덕션 코드에서는 해당 부분이 필요하지 않았고,
만약 그렇게 코드를 작성했다면 본문을 가져오는 과정에서부터 오류가 발생했을 것이다. 또한, 현재 작성한 부분은 생성 API가 아직
만들어지지 않은 상태로 조회 API를 만들다 보니 생성을 위한 엔티티를 만드려고 &apos;피드 노드들&apos; 엔티티를 조회해온 코드여서
추후 생성 API가 만들어진다면 제거될 부분이긴 하다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;cf. findFirst~() 메서드에서는 트랜잭션이 어딨을까?&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContentRepository&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JpaRepository&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findFirstByFeedOrderByCreatedAtDesc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt; feed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;feedContentRepository의 경우 위와 같이 JpaRepository를 상속받고 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3097b7de8121b62a802b0adeadec0f5d/00f4c/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 14.117647058823529%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAgklEQVR42n2MSxLCIBAFuYd8whD+EFQ2uf/FniMV3emiq6umX40g2nGeDXNW9KMipAqzOWhDP/jXCEIbux44H/nhHeQ8dkuQalto/bbFjZGaLc3VzHej+K4uixA7aozIIaKVhtYfOMYTnZ1Kh44ZhRk5IafCbaK2sXYffK6w3Cx5vADHBVVZAulJVQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/3097b7de8121b62a802b0adeadec0f5d/ca1dc/3.png&apos; srcset=&apos;/static/3097b7de8121b62a802b0adeadec0f5d/e7570/3.png 170w,
/static/3097b7de8121b62a802b0adeadec0f5d/f46e7/3.png 340w,
/static/3097b7de8121b62a802b0adeadec0f5d/ca1dc/3.png 680w,
/static/3097b7de8121b62a802b0adeadec0f5d/02d09/3.png 1020w,
/static/3097b7de8121b62a802b0adeadec0f5d/9d567/3.png 1360w,
/static/3097b7de8121b62a802b0adeadec0f5d/00f4c/3.png 1568w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이때, JpaRepository 인터페이스의 구현체인 SimpleJpaRepository 클래스를 가면 위와 같이 &lt;code class=&quot;language-text&quot;&gt;@Transactional&lt;/code&gt;이 붙어 있는 것을 볼 수 있다. 그렇기 때문에 해당 메서드가 호출하는 시점에 대해서만 트랜잭션이 걸려있게 되는 것이다.&lt;/p&gt;
&lt;p&gt;기본적으로 스프링에서 영속성 컨텍스트는 트랜잭션과 생명주기가 동일하기 때문에, feedContentRepository로부터 조회해온 FeedContent는 트랜잭션이 종료되면서 영속성 컨텍스트의 관리 범위에서도 함께 벗어나게 된다. 현재 피드 본문 엔티티는 준영속 상태가 되었음을 기억하자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Here!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;다시 돌아와서, here! 이라고 특정된 부분을 보자. 해당 부분이 오류가 발생하는 지점이다.
피드 본문으로부터 노드에 대한 정보를 가져오려고 할 때 오류가 발생한 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;노드에서 getValues() 메서드를 호출하면 values()에 대한 접근이 일어나게 되는데, 이때 아래와 같은 일들이 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/34d3a066ef250329508637108cbbc5f5/3643c/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 20%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAYAAACOXx+WAAAACXBIWXMAABYlAAAWJQFJUiTwAAABKElEQVR42j2PMUtCYRSG79ZUEIRFBVENmlKUXUXzIiSCSyEGQQ7RL2kokNQgCkI0KdPBagiCGvoTZUJe7r0q4Zql4BCF6NOngwcezssZDu8jFV5fODmOcHYaJxaNEI1FicePODzYp/hWoDfdbpd2u81HtUpVV6no71S0ktgqhqFTLutoapFm4wspmThnzDTDojvE9IIfk3WTKVuAoXEHudsn8a5Do9FE0zTk5RXsrg0c3jCryjayK8DS2hayb48JS4BM/hEpkUwxPDqJ2eZhzqwwb1OYtbgYMVnJ3z30G/ba1Wo13Mo6diWEy7+L0xfG6Q0KQnh8O5jlIDf3z0glVeUinSabzZC9vuqTE/kynaJsGAPljqDVatH8rgs+hV69rzhA3P5+f/gHRVreTRRY+QcAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;4&apos; title=&apos;&apos; src=&apos;/static/34d3a066ef250329508637108cbbc5f5/ca1dc/4.png&apos; srcset=&apos;/static/34d3a066ef250329508637108cbbc5f5/e7570/4.png 170w,
/static/34d3a066ef250329508637108cbbc5f5/f46e7/4.png 340w,
/static/34d3a066ef250329508637108cbbc5f5/ca1dc/4.png 680w,
/static/34d3a066ef250329508637108cbbc5f5/02d09/4.png 1020w,
/static/34d3a066ef250329508637108cbbc5f5/9d567/4.png 1360w,
/static/34d3a066ef250329508637108cbbc5f5/3643c/4.png 1400w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;read() 라는 메서드를 따라 들어가다 보면, 어떠한 초기화 작업이 처음에 발생하는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b99d64a6feb4410c07e0dc76b934fcaa/44982/5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 47.05882352941176%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABPklEQVR42pVS7U7EIBDse1goUL6hpdfT0+R+GPX9n2lc6F1jvcTEH5OlCzs7M2mnjIWNEWkqCClDWQcdArT3qHf1u1apLUbnW18oDS4UBjE28EHt6ORtqJzfMBNcJuJygp8WiNFgoOF7ZUyi78WGpw21dyB0RDaHiJxmFCJJywXmdEUqL8gxYEp0R+pTXuBKwvnrFeX9jPXjgvXzgvg8H0g7QZK99VhTQXYTxtG2i+GAEUKQUq2hvN0xBgdpDDj/ofCew0CZME6WeN12tLGDBpsaelMrY6qdD5Yrmfe5WYpk28eMECdYn9Az0ZY84rHf33qNUEiyQlantOCU1z0zH2lB2BZEiqTW3/AuwGlPcRUYHdDxYbNbfwNDpKk+oEyFNG2JVOZPVDGyCpK2nbt7sypllEF/y5H9BzTHBtnwDeDu/6Rpe7xxAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;5&apos; title=&apos;&apos; src=&apos;/static/b99d64a6feb4410c07e0dc76b934fcaa/ca1dc/5.png&apos; srcset=&apos;/static/b99d64a6feb4410c07e0dc76b934fcaa/e7570/5.png 170w,
/static/b99d64a6feb4410c07e0dc76b934fcaa/f46e7/5.png 340w,
/static/b99d64a6feb4410c07e0dc76b934fcaa/ca1dc/5.png 680w,
/static/b99d64a6feb4410c07e0dc76b934fcaa/02d09/5.png 1020w,
/static/b99d64a6feb4410c07e0dc76b934fcaa/9d567/5.png 1360w,
/static/b99d64a6feb4410c07e0dc76b934fcaa/44982/5.png 1592w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;그리고, 지연 로딩 작업을 세션으로부터 컬렉션 정보를 초기화하는 것을 볼 수 있다.
상위의 주석을 잘 읽어보면, 초기화가 불가능할 때 &lt;code class=&quot;language-text&quot;&gt;LazyInitializationException&lt;/code&gt;이 발생함을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/034fbb233de32ecbca89850f4be518a6/37cfc/6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.35294117647059%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABEUlEQVR42k2QaZKCMBSEOYgkkJU1IIKCeglHx6m5/0F6moBV8+Or7s7y0pXEWYdjf0JN2mFGfZypC7rxirI7o59uGMYL2qZDaAKcr2BdCWU8dfMrvqihtEMipELBhVD0KGyJ2vGgKZBJTRQkOaTZjoyaijyy+eyfz5HITCPPNZoqYDouGANbNSecqGPHZu0QW618WqwlRMbHeFcQubOux4FZbqCUhbWeFwyzgjZ2Q1sYs+LguJ9JtjkIpOkHiZRZiI1EcpjmgKa/o7r+opy/US0/1Df1Hb2/vKDPD6jpAXP5gp0JVU/PmB2zmV7IhycSzX+zvobx/MNwJ7eN7o4ybPj2CtsuO3PErNTMzZ7pdbXgD5YhspjJXY3+AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;6&apos; title=&apos;&apos; src=&apos;/static/034fbb233de32ecbca89850f4be518a6/ca1dc/6.png&apos; srcset=&apos;/static/034fbb233de32ecbca89850f4be518a6/e7570/6.png 170w,
/static/034fbb233de32ecbca89850f4be518a6/f46e7/6.png 340w,
/static/034fbb233de32ecbca89850f4be518a6/ca1dc/6.png 680w,
/static/034fbb233de32ecbca89850f4be518a6/02d09/6.png 1020w,
/static/034fbb233de32ecbca89850f4be518a6/9d567/6.png 1360w,
/static/034fbb233de32ecbca89850f4be518a6/37cfc/6.png 1492w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;그리고, 해당 메서드를 타고 들어가면 session 정보가 없을 때 외부의 트랜잭션을 사용할 수 있는지 판단하는데, 사용 불가능하기 때문에 (allowLoadOutsideTransaction=false) 하단의 else 구문으로 제어가 내려가게 되어 오류가 발생하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/90fe99244c150056b3faf47ccf9379d3/9ac8b/7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 37.64705882352941%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAABUUlEQVR42m1RW3KDMAzkGmkC5m3wC8ybZNpOT5D2/ofZynbDtJl+rCxpxEq7RJNW6IWEFgqFXsC7FaXZkMkZmRgp31HqDYVaAiiv5QAuG7x/XvHxdcPrfcPbffd1lOclZhrazQ2zmrDpEV3bQ9cGopJgSYY4Zk9ICRlOp9jj5YXhfE4JDFHCCrC0QJZW6BpLZAOsXbDMV4zDCjssmOYd47RhGBf/jtMKbSyquiG0yIsaCcs9T5RQiKm4JLTBgS4oabCVGpxscK9QHYQ0B1qhCQZS9VDaouYCMSlxpJELdVljkBNJXrEQhnaC4RZ9Q9e2I7SysGRHL8aggGbbRtN3JaqK0zGBzBN6uXlFfmmYhjbyDpr3aGsFyUNPyg7GDP595O7CNAt2Pcg8odPvmpc4yH3AWXD0LgGu9r2f/DfRQeiC08/cz2F/t4Vefhj+H8Ez4TctKujbltIYcAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;7&apos; title=&apos;&apos; src=&apos;/static/90fe99244c150056b3faf47ccf9379d3/ca1dc/7.png&apos; srcset=&apos;/static/90fe99244c150056b3faf47ccf9379d3/e7570/7.png 170w,
/static/90fe99244c150056b3faf47ccf9379d3/f46e7/7.png 340w,
/static/90fe99244c150056b3faf47ccf9379d3/ca1dc/7.png 680w,
/static/90fe99244c150056b3faf47ccf9379d3/02d09/7.png 1020w,
/static/90fe99244c150056b3faf47ccf9379d3/9ac8b/7.png 1350w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;참고로, allowLoadOutsideTransaction의 경우 제일 처음 세션 정보를 세팅해줄 때 위의 메서드에서 적용된다.
세션 정보로부터 지연 로딩임에도 트랜잭션을 사용할 수 있는지 정보를 받아오는 것 같다.&lt;/p&gt;
&lt;p&gt;그렇다면 트랜잭션 정보가 있으면 되는 게 아닐까?
한 번 천천히 해결해나가보자.&lt;/p&gt;
&lt;h3&gt;그냥 @Transactional을 붙이면 되지 않나?&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@Transactional&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 트랜잭션!&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 테스트&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonProcessingException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
	
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 카테고리 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_카테고리를_저장한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;이커머스&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 제목&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 소개글&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 본문&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드_본문 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 피드_카테고리를_저장한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; 카테고리_이름&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 피드_카테고리 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;카테고리_이름&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; feedCategoryRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_카테고리&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;트랜잭션이 없어서 생긴 문제라면, &lt;code class=&quot;language-text&quot;&gt;@Transactional&lt;/code&gt;을 붙이면 된다고 생각할 수 있다.
여기서 아까 예제와 다르게 피드에 대한 카테고리 생성 메서드가 추가된 것을 볼 수 있는데, 오류가 발생한 포인트이기 때문에 넣어두었다. 카테고리의 경우 생성하는 API가 없기 때문에 (나중에 admin 기능을 추가하면 넣을 예정이었다.) 위와 같이 직접 save를 해준다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/89ca75e9567bb7f314b42b263011c1ac/5e982/8.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 9.411764705882353%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAZklEQVR42i2N2w2AMAwDGQQJ6Js2paVI7L+ZcYCP0zmRo0xiI7JLyLTQRfG/TUCxAaImjZ2T+4PutM5K11v2zGox3SGjJUFPlQjGXnGVjpPW4tBnxiNsHklhjtuHf3HMDutiMS8GD1rvOlAL4cAcAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;8&apos; title=&apos;&apos; src=&apos;/static/89ca75e9567bb7f314b42b263011c1ac/ca1dc/8.png&apos; srcset=&apos;/static/89ca75e9567bb7f314b42b263011c1ac/e7570/8.png 170w,
/static/89ca75e9567bb7f314b42b263011c1ac/f46e7/8.png 340w,
/static/89ca75e9567bb7f314b42b263011c1ac/ca1dc/8.png 680w,
/static/89ca75e9567bb7f314b42b263011c1ac/02d09/8.png 1020w,
/static/89ca75e9567bb7f314b42b263011c1ac/9d567/8.png 1360w,
/static/89ca75e9567bb7f314b42b263011c1ac/5e982/8.png 1892w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;하지만, 정말 뜬금없이 NPE가 발생하는 것을 볼 수 있다. 이는, 응답값이 제대로 반환되지 않으면서 response header 값이 제대로 내려오지 않았기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/bdc2c24edddbbc03251d94c0ba608916/e9bec/9.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 15.88235294117647%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAqElEQVR42iXOUXKDMAxF0eykbQqExAZblrAdQvrV/W/p1rgfb55mpNGcy3z3SNoI0YhRCVJY0tHyxsdC0oJI24mimjHbcKFyWyqP8OR6S3wNnvnuGMaZy/V7wrbKlp+oVXLrUvaec86tNR+IvZD8w2K/jP7F6AqTr0TdWRvm/PPxOfw/VCs9oUnCqexSYw3ajhNr2vFydLmL7y50i+BXRZr6vB+nRxf+AWDlXdVryuVcAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;9&apos; title=&apos;&apos; src=&apos;/static/bdc2c24edddbbc03251d94c0ba608916/ca1dc/9.png&apos; srcset=&apos;/static/bdc2c24edddbbc03251d94c0ba608916/e7570/9.png 170w,
/static/bdc2c24edddbbc03251d94c0ba608916/f46e7/9.png 340w,
/static/bdc2c24edddbbc03251d94c0ba608916/ca1dc/9.png 680w,
/static/bdc2c24edddbbc03251d94c0ba608916/02d09/9.png 1020w,
/static/bdc2c24edddbbc03251d94c0ba608916/9d567/9.png 1360w,
/static/bdc2c24edddbbc03251d94c0ba608916/e9bec/9.png 1392w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;실제로 해당 로그의 상단으로 올라가보면, 위와 같이 카테고리에 대한 Exception이 발생한 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b1f06725795f8534b9ec364bd5292dab/e9bec/10.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 27.647058823529413%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABVUlEQVR42l2RW0vDQBSE82ZBX1TokxYvBRu1bXaTtKgF/RdKxUttkzZJG1tF/6+X2psIio+6n6sRoS4MZ2Y5c9g9Y/D/fH7CywTGA3gew2QEb68weIT+vdbDhL+//RrUlN3wmwGX3Ss6nS5x3CWKb2hGt7TCG4LgkjiKaYedpAYR3bhHFGje7tGOr/BbHTw/IAjbVI9PMBYW01jCZXPLImfmKRQltuPguCWkFJpLhCj+QNqSorRZy1msm5KsaZFZy7OUybKymmUmNYsxv5DWpjL5gsDUQx3LYt8VHJQdKralIdgr7bLj7lJ2KrjOAaJYwtT9BekgbJeN3DbLmVVSqTmM6vGp/vI1YZQ83btoaHg0ao0E53Wtfbya94fv+/pZjfr5BfVGE78Z0tLrODyqYkxtVCnUaIiajHUdoIZ9VP8BpUNQOhA10Hr0lPR888c7+PiYCuULM6gwgiWdvvsAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;10&apos; title=&apos;&apos; src=&apos;/static/b1f06725795f8534b9ec364bd5292dab/ca1dc/10.png&apos; srcset=&apos;/static/b1f06725795f8534b9ec364bd5292dab/e7570/10.png 170w,
/static/b1f06725795f8534b9ec364bd5292dab/f46e7/10.png 340w,
/static/b1f06725795f8534b9ec364bd5292dab/ca1dc/10.png 680w,
/static/b1f06725795f8534b9ec364bd5292dab/02d09/10.png 1020w,
/static/b1f06725795f8534b9ec364bd5292dab/9d567/10.png 1360w,
/static/b1f06725795f8534b9ec364bd5292dab/e9bec/10.png 1392w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이는, 피드 생성 API가 호출되면서 create 하는 과정에 request body 값으로 받은 피드 카테고리 아이디에 대한 유효성을 검증하게 되고, 해당 로직에서 카테고리 정보가 존재하지 않아 발생한 오류이다.&lt;/p&gt;
&lt;p&gt;분명 위에서 &lt;code class=&quot;language-text&quot;&gt;피드_카테고리를_저장한다()&lt;/code&gt; 메서드를 통해 저장을 했는데, 이게 어떻게 된 일일까?
이는, &lt;code class=&quot;language-text&quot;&gt;@SpringBootTest&lt;/code&gt;(webEnvironment = SpringBootTest.WebEnvironment.RANDOM&lt;em&gt;PORT) 때문이다.
이전에 테스트 컨텍스트에 대한 블로그 글을 읽은 적이 있는데, 그때 random&lt;/em&gt;port 옵션에 대해 이와 같이 커멘트를 봤었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;만약 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)을 사용하게 된다면 실제 웹 환경이 구성
되기 때문에 다른 컨텍스트 정보를 지정하게 되면 다른 웹 서버가 띄워지게 된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;random_port 옵션을 지정하게 되면 별개의 스레드에서 컨테이너가 실행된다는 것이다.
= 즉, 프로덕션 코드에서 작성한 메서드의 스레드와 &lt;code class=&quot;language-text&quot;&gt;@SpringBootTest&lt;/code&gt;의 메서드의 스레드가 다르다는 의미이다.&lt;/p&gt;
&lt;p&gt;기본적으로 &lt;code class=&quot;language-text&quot;&gt;@Transactional&lt;/code&gt;이 붙게 되면 작업 스레드는 커넥션 풀에서 Connection 객체를 가져와서 사용하게 되는데, 스레드가 달라지게 되면 사용하게 되는 Connection이 달라지게 된다. 즉, 트랜잭션이 아예 달라지게 되는 것이다.
그렇기 때문에 프로덕션 코드가 실행되는 피드 생성 API의 스레드 입장으로서는 테스트 메서드인 피드&lt;em&gt;카테고리를&lt;/em&gt;생성한다() 스레드가 하는 일을 인식하지 못하기 때문에 카테고리에 대한 정보를 받아올 수 없는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0727e93f28f2c5cbddf6fadacc458661/46608/11.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 33.529411764705884%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAxElEQVR42qWSxw6DMBBE+ZCEYlNcqKYk+f8Pm3gWgaIcciCH0ZqV9WZncRLmDbpskOUahaqkppm6rISQKazw7YDGeChd454W14EEDOMM5/u/QCfQ2A7Gtqhqi7wocbvnJ5j1lz5Bx7cA226UyL4dJTbXQDjF87eO/gmKe2dSAS7rE2F5YNleCGFDP+zxOTHF6WlCsW/drv2OExDFYZRukHB/47RGUJDKH8QeL7DX9VNMMIkR4bo0KKuoaGZdJ0acmOZ8LW/S3ceMs6w6cAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;11&apos; title=&apos;&apos; src=&apos;/static/0727e93f28f2c5cbddf6fadacc458661/ca1dc/11.png&apos; srcset=&apos;/static/0727e93f28f2c5cbddf6fadacc458661/e7570/11.png 170w,
/static/0727e93f28f2c5cbddf6fadacc458661/f46e7/11.png 340w,
/static/0727e93f28f2c5cbddf6fadacc458661/ca1dc/11.png 680w,
/static/0727e93f28f2c5cbddf6fadacc458661/02d09/11.png 1020w,
/static/0727e93f28f2c5cbddf6fadacc458661/9d567/11.png 1360w,
/static/0727e93f28f2c5cbddf6fadacc458661/46608/11.png 1864w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;여기서 한 가지 실수를 했는데, 콘솔상으로는 쿼리가 발생하길래 계속 insert가 된다고 생각했었다. (IDENTITY 전략으로 인해)&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 560px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d5b0818ebea904a347d00726cc306f0d/6d7b8/12.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 35.88235294117647%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAAA9UlEQVR42qWQy3KDIBSGeY9qVEAQwQImTlLH2EW106w72djpsu//CH8hvUyv2WTxDQPn43D4CdseUNod+n6P7c2IpvFIkgzpqviTVUaRRtI87PNfdcLKGoxX0HUDIWtI04JJA8ZEOJcnKBcQpQKlAlnBUVAOrq7BhQ71L164Q6zb4OXZYVn2GIc7dIcF7XAPax1822HXD3B+g+PtiGme8HhcME8z1g9PaPsJznpYt/70SJyqNgrKGxjjIZU5TfqBrDSEqEMUGso24aEO2liIKnr6m1cKBRL/naSBJK75v9lFJw1chXzPeSSG/AZ7h14EubTBz4avqRPLBKMHJaYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;12&apos; title=&apos;&apos; src=&apos;/static/d5b0818ebea904a347d00726cc306f0d/6d7b8/12.png&apos; srcset=&apos;/static/d5b0818ebea904a347d00726cc306f0d/e7570/12.png 170w,
/static/d5b0818ebea904a347d00726cc306f0d/f46e7/12.png 340w,
/static/d5b0818ebea904a347d00726cc306f0d/6d7b8/12.png 560w&apos; sizes=&apos;(max-width: 560px) 100vw, 560px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;하지만, 실제로 DB에 가서 확인해보니 결과가 저장되지 않았었고, 아마 쿼리만 발생한 것 같다고 추측된다.
(트랜잭션 시작 후 커밋이 되지 않은 상태라고 보는 게 더 정확할 것 같다.)&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 560px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e84ce41daa1c56c24d5600d4653755d9/6d7b8/13.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 35.88235294117647%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAABFUlEQVR42o2R206DQBCGeQ85HxbYLSwslFJaLWJt5V5jTPQJvPT98zts2pDYNvHiy2R2/0wm3xjBakQkW3TdPVbrB2S5gmnasGzvKrbja3RvORf/Rsg4/CBGmi4IgSjmCHmBIEoQhLHGD5iuLErh+RFcN9BvOhfOuQkjlxWaZYWf7wzPhwGPwxHq5RNls4WUJap6habdoC5qvD/12B9HvL59YDccoMYvlHULWSgoyrXrLQwWCyREWiYQuYQQEizhhACjbScSvgBPMkiVIysVChrORX7KzLmYesPzGRwvJG8+4cK03NkJubozHaQ80267TY9dv0eplqeMe+nQpWGeR16o3mLydmZyNy1xK2ucr/Yf/l76Gr8bl80Xrj5q3AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;13&apos; title=&apos;&apos; src=&apos;/static/e84ce41daa1c56c24d5600d4653755d9/6d7b8/13.png&apos; srcset=&apos;/static/e84ce41daa1c56c24d5600d4653755d9/e7570/13.png 170w,
/static/e84ce41daa1c56c24d5600d4653755d9/f46e7/13.png 340w,
/static/e84ce41daa1c56c24d5600d4653755d9/6d7b8/13.png 560w&apos; sizes=&apos;(max-width: 560px) 100vw, 560px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;@Transactional&lt;/code&gt;을 제거하면 위와 같이 레코드가 저장된다. (트랜잭션이 없으니 바로 DB에 저장)&lt;/p&gt;
&lt;p&gt;그러면 이 문제를 어떻게 해결해야 할까?
RANDOM_PORT를 사용하지 않게 되면 E2E 테스트의 의미가 없고, API call로 대체할 수 없는 상황이다.&lt;/p&gt;
&lt;h3&gt;지연 로딩이 필요한 시점에서만 트랜잭션을 생성하기 - 메서드 분리하기&lt;/h3&gt;
&lt;p&gt;근본적인 문제는, 지연 로딩을 하는 시점에 트랜잭션이 존재하지 않아 조회를 해올 수 없었던 것이다.
그렇다면 조회하는 시점에 새로운 트랜잭션을 생성해주는 건은 어떨까?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 테스트&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonProcessingException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
	
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 카테고리 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_카테고리를_저장한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;이커머스&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_노드들을_반환한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;token annotation punctuation&quot;&gt;@Transactional&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 트랜잭션!&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들을_반환한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; 액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedNodeSaveRequest&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                        &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedNodeSaveRequest&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 제목&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 소개글&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 본문&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드_본문 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; 피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;하지만, 위 코드는 동작하지 않는다. 이는 기본적으로 &lt;code class=&quot;language-text&quot;&gt;@Transactional&lt;/code&gt;은 Spring AOP를 사용하여 구현되기 때문이다.&lt;/p&gt;
&lt;p&gt;이때 크게 2가지의 특징이 존재한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;타겟 클래스를 상속하여 프록시 객체를 생성하기 때문에 상속 자체가 불가능한 private 메서드에 대해서는 적용 불가&lt;/li&gt;
&lt;li&gt;동일한 클래스의 내부 메서드를 호출하게 되면 프록시를 호출하지 않고 대상 객체를 직접 호출하게 되어 적용 불가&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;위 코드에서는 2번의 경우, 내부 메서드를 사용했기 때문에 트랜잭션을 적용할 수 없는 것이다.
그렇다면, 내부 메서드 대신에 외부 클래스를 활용하면 되지 않을까?&lt;/p&gt;
&lt;h3&gt;지연 로딩이 필요한 시점에서만 트랜잭션을 생성하기 - 클래스 분리하기&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Component&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@TestConstructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;autowireMode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AutowireMode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ALL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedTestHelper&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedRepository&lt;/span&gt; feedRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContentRepository&lt;/span&gt; feedContentRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedTestHelper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedRepository&lt;/span&gt; feedRepository&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                             &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContentRepository&lt;/span&gt; feedContentRepository&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feedRepository &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; feedRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feedContentRepository &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; feedContentRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Transactional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;readOnly &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들을_조회한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드_본문 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; 피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Feed&lt;/span&gt; 피드 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; feedRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; feedContentRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findFirstByFeedOrderByCreatedAtDesc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;피드 노드를 조회하기 위한 별도의 Helper 클래스를 생성해준다.
피드_본문 엔티티가 detached 상태가 되지 않도록 조회를 해오는 시점의 메서드부터 helper 클래스에 두었으며, 본문으로부터 노드 정보를 지연로딩을 통해 가져와서 반환하도록 만들었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 테스트&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonProcessingException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
	
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 카테고리 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_카테고리를_저장한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;이커머스&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 제목&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 소개글&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 본문&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// Here!&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; feedTestHelper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;피드_노드들을_조회한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그리고 기존의 테스트 코드에서 helper 클래스를 통해서 노드를 조회해왔다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2e96602620600db6b654ffea6bd41d2c/a2906/14.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 27.058823529411764%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAoklEQVR42qWQWQ6DMAxEc48CCVmBsBUQS4t6/1tN40TtX1Wp/Xh2Yo3GIzPrPNbthDIVLhlHXpQouPwZRgbWNajqFnXTwdgaxR+mjIpUFv0wo/E9lHbIcvEWvBKnnqD3JxgXKhr5bowJpXKgGZlwoVFKE/+i1F8hHZvmFfOyY1kPHLcHtv3EeF3CXe8h9QTfDsHUxpNEwlJX+RSiTSEI0tH8CSigjiRTdrmpAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;14&apos; title=&apos;&apos; src=&apos;/static/2e96602620600db6b654ffea6bd41d2c/ca1dc/14.png&apos; srcset=&apos;/static/2e96602620600db6b654ffea6bd41d2c/e7570/14.png 170w,
/static/2e96602620600db6b654ffea6bd41d2c/f46e7/14.png 340w,
/static/2e96602620600db6b654ffea6bd41d2c/ca1dc/14.png 680w,
/static/2e96602620600db6b654ffea6bd41d2c/02d09/14.png 1020w,
/static/2e96602620600db6b654ffea6bd41d2c/9d567/14.png 1360w,
/static/2e96602620600db6b654ffea6bd41d2c/a2906/14.png 1460w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;하지만, 위 방법은 매우 찝찝하다. 지연로딩이 필요한 코드마다 이렇게 테스트 클래스로 분리해야 하기 때문이다.
만약 테스트하는 케이스가 정말 많아진다면 그럴 때마다 helper 클래스에 메스드가 엄청나게 늘어나게 될 것이다.
이는 전혀 개발자답지 못한 해결 방법이기 때문에 다른 방법을 모색할 필요가 있다.&lt;/p&gt;
&lt;h3&gt;지연 로딩이 필요한 시점에서만 트랜잭션을 생성하기 - 함수형 인터페이스 활용하기&lt;/h3&gt;
&lt;p&gt;필요할 때마다 helper 클래스의 메서드로 분리하는 게 아니라, 트랜잭션이 필요한 로직에 대해서만 외부 클래스에서 실행되도록 만들 수는 없을까? 즉, 메서드를 인자로 넘겨서 어떠한 곳에서 처리하고 싶은 것이다.&lt;/p&gt;
&lt;p&gt;자바에서는 메서드를 파라미터로 전달하기 위해서 람다식을 활용할 수 있다.
우리는 인자로 넘긴 값으로 List&lt;FeedNode&gt;를 받아야 하기 때문에 T를 반환하는 시그니처를 가진 함수형 인터페이스를 하나 설정할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@FunctionalInterface&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionalTask&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;함수형 인터페이스란?
오직 1개의 추상 메서드를 가지는 인터페이스.
여기서 추상 메서드란, 자식 클래스에서 반드시 오버라이딩 해야 사용할 수 있는 메서드이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그리고, 트랜잭션이 필요한 작업을 도와준다는 의미로 하나의 헬퍼 클래스를 생성하도록 하자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Component&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionHelper&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Transactional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;readOnly &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionalTask&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;헬퍼 클래스에서는 TransactionTask 타입의 어떠한 람다식을 받아서, 해당 람다식을 &lt;code class=&quot;language-text&quot;&gt;@Transactional&lt;/code&gt;이 걸린 상태로 실행해주는 역할을 진행한다. 이제 이 헬퍼 클래스를 활용하게 되면 아래와 같이 테스트 코드를 작성할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 테스트&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonProcessingException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
	
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 카테고리 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_카테고리를_저장한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;이커머스&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 제목&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 소개글&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 본문&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transactionHelper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionalTask&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드_본문 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; 피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;transactionHelper 클래스의 getResult() 메서드의 인자로 함수형 인터페이스의 추상 메서드인 execute()의 익명 클래스가 들어간다.
그리고, 해당 구현체에 피드 본문을 조회하여 피드 노드를 반환하는 로직을 넣었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;익명 클래스&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;클래스의 선언과 인스턴스화를 동시에 진행할 수 있는 클래스로, 이름이 없는 클래스라 익명 클래스라고 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이때, 익명 클래스의 경우 람다로 축약할 수 있기 때문에 아래와 같이 더 간결하게 리팩터링을 진행할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 테스트&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonProcessingException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
	
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 카테고리 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_카테고리를_저장한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;이커머스&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 제목&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 소개글&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 본문&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transactionHelper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    	&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드_본문 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; 피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/471d29e9e8f27817493a54dfcd8eb25f/e596b/15.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 37.05882352941176%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAy0lEQVR42p2QzQ6CMBCEeRChLRQoFCg/ionx4Pu/1LizqPHMYbrJFL7uTLbvOx7PF9puEEUEmXXbn1aWFyVCEFiIqJsOjZjWVigKd0oCdCirBst60+2MwKjClKeU8WDcrh/h64BLbk/DFGisRxxmDOOMPk4SOcKVzW9TyjoPI7If/d99QfQVGIeEdbuLdp3zcgU9dupcrZ2ybC/90mMtxzwSEUJwkISsToHsj0rzhpRWJIGO06o/j9Oi2zMFv+UDbeg1CaH0COKjvHsDC2vIvsooNvUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;15&apos; title=&apos;&apos; src=&apos;/static/471d29e9e8f27817493a54dfcd8eb25f/ca1dc/15.png&apos; srcset=&apos;/static/471d29e9e8f27817493a54dfcd8eb25f/e7570/15.png 170w,
/static/471d29e9e8f27817493a54dfcd8eb25f/f46e7/15.png 340w,
/static/471d29e9e8f27817493a54dfcd8eb25f/ca1dc/15.png 680w,
/static/471d29e9e8f27817493a54dfcd8eb25f/02d09/15.png 1020w,
/static/471d29e9e8f27817493a54dfcd8eb25f/9d567/15.png 1360w,
/static/471d29e9e8f27817493a54dfcd8eb25f/e596b/15.png 1862w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;최종적으로 실행해보면 위와 같이 테스트 코드도 잘 실행되는 것을 볼 수 있다! &lt;/p&gt;
&lt;p&gt;이제 테스트 코드에서 지연로딩이 필요한 부분에 대해 (then절 같이 응답값을 꺼내어 검증할 때) 이를 잘 사용하면 된다.
오랜만에 함수형 인터페이스 같은 개념을 보다 보니까 헷갈렸는데, 아무쪼록 잘 해결할 수 있어서 다행이다.
꽤 의미있는 트러블 슈팅을 한 것 같아서 재밌었다 &lt;/p&gt;
&lt;h3&gt;추가&lt;/h3&gt;
&lt;p&gt;더 좋은 방법을 찾게되어서 작성해보고자 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowird&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionTemplate&lt;/span&gt; transactionTemplate&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 테스트&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonProcessingException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
	
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 카테고리 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_카테고리를_저장한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;이커머스&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 제목&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 소개글&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 본문&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transactionTemplate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionCallback&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doInTransaction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionStatus&lt;/span&gt; status&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드_본문 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; 피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;스프링에서는 이미 TransactionTemplate 이라는 인터페이스를 통해서 제공을 해주고 있었다..
위와 같이 반환값이 필요한 경우라면 TransactionCallback을 인자로 받으면 된다.
람다를 활용하면 더 축약이 가능하다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowird&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionTemplate&lt;/span&gt; transactionTemplate&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 테스트&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonProcessingException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
	
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 카테고리 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_카테고리를_저장한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;이커머스&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 제목&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 소개글&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 본문&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FeedNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; 피드_노드들 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transactionTemplate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드_본문 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; 피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;지금 보면 직접 만든 transactionHelper와 완전 동일하다고 봐도 무방하다. 그냥 요렇게 사용하는 게 더 좋을 것 같다.&lt;/p&gt;
&lt;p&gt;만약, 반환값이 필요없다면 TransactionCallbackWithoutResult를 인자로 받으면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowird&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionTemplate&lt;/span&gt; transactionTemplate&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; 테스트&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonProcessingException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
	
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedCategory&lt;/span&gt; 카테고리 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드_카테고리를_저장한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;이커머스&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; 피드_아이디 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드를_생성한다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;액세스_토큰&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 카테고리&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 제목&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 소개글&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;피드 본문&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;노드&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 노드&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    transactionTemplate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionCallbackWithoutResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doInTransactionWithoutResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransactionStatus&lt;/span&gt; status&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FeedContent&lt;/span&gt; 피드_본문 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 피드로부터_본문을_가져온다&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;피드_아이디&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                피드_본문&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[JPA] 1:N fetchJoin과 limit을 함께 사용하여 발생한 OutOfMemory 문제 해결]]></title><description><![CDATA[들어가며 톰캣 성능테스트를 하기 위해 특정 API에 대하여 한 번에 많은 요청을 보냈고, 평소에 잘 동작하던 API가 OutOfMemoryError…]]></description><link>https://hoonblog.netlify.app/jpa-out-of-memory/</link><guid isPermaLink="false">https://hoonblog.netlify.app/jpa-out-of-memory/</guid><pubDate>Wed, 10 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;톰캣 성능테스트를 하기 위해 특정 API에 대하여 한 번에 많은 요청을 보냈고, 평소에 잘 동작하던 API가 OutOfMemoryError를 던지면서 모든 요청에 대해 실패하였다.
이 문제를 해결하기 위해 어떤 과정을 거쳤는지 자세히 살펴보자&lt;/p&gt;
&lt;h2&gt;[문제 상황]&lt;/h2&gt;
&lt;p&gt;톰캣 성능테스트를 하기 위해 Jmeter를 사용하였고, 1초에 500번의 피드 목록 조회 요청을 보내도록 설정했다.
그런데 500번의 요청이 모두 실패했고, 어떤 에러 메세지가 담겨있는지 확인했다.
메세지는 다음과 같았다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Handler dispatch failed: java.lang.OutOfMemoryError: Java heap space&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;상상도 못한 OutOfMemoryError가 발생했다. 이전에는 한 번도 만나보지 못했던 에러였다.&lt;/p&gt;
&lt;p&gt;바로 어플리케이션의 로그를 확인했다.
그리고 다음과 같은 경고가 떠 있는 것을 발견할 수 있었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[WARN] [http-nio-9000-exec-483] [org.hibernate.orm.query] - HHH90003004:
firstResult/maxResults specified with collection fetch; applying in memory&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;바로 쿼리에 문제가 있었다는 것을 알게되었다.
그럼 피드 목록 조회 요청 때 사용하는 쿼리를 살펴보자!&lt;/p&gt;
&lt;h2&gt;[엔티티 연관관계]&lt;/h2&gt;
&lt;p&gt;그 전에 이해를 돕기 위해 엔티티의 연관관계에 대해서 간단하게 설명하면&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&apos;피드&apos;와 &apos;피드 태그&apos;라는 엔티티는 1:N 관계이다.&lt;/li&gt;
&lt;li&gt;한 &apos;피드&apos;에 대하여 &apos;피드 태그&apos;는 최소 1개부터 최대 5개까지 존재할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;문제의 쿼리&lt;/h3&gt;
&lt;p&gt;무한 스크롤을 위해 피드 목록을 가져올 때 요청받은 사이즈만큼 피드를 전달하는데, 이때 피드와 피드 태그를 모두 반환한다.
피드 태그는 지연 로딩으로 설정해놓았기 때문에, N+1 문제를 방지하기 위해 fetchJoin을 붙여 한 번에 가져오도록 했다.&lt;/p&gt;
&lt;p&gt;다음은 실제 QueryDsl로 작성한 쿼리문이다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4024fb04f51fd8a89a7bb5bd3874fc12/84e61/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 54.11764705882353%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAABgUlEQVR42o2SR47cMBBF+zK2NCIlijkptaYdx/DO8P1P8v0ltzE7Q4sCU9WrwH9b8o61bqjThJBn2PIFbvoKXT5D+RVOLXAhI6YCYxMcbRwz9DgjpAzPt+Pe2gilA26djHiRAWKw6KRB0wc0Q0ajEoQqiOMrQixIDA6uIuoNwSwosRKW0I/hNDl4+nvcXnoHPcwYzAoRHzBhhrceUjomcEzk0NPx8Gt5bsVz5bkRT5PvewI9A0nXFfr1N+L9O2pMKKzOjgmRLXl/VOLPgBP2HzuBjWS7KmBc3ji/Hc4FwiK04cq9UPasopVXgcysbIBZviHOG5Lz8JxL4JAN71PiCA7o5QqFRW8z3P4Dlj+tHFs0iUk8lOGMrcOg3aUqT+DfA8GdgUyUy/0Xwv0Nj33FUidstaLS3n0vAHtWoGNGXSbkdUPh+mlLWBfKwmh0lNXlGbZsWbLF8PiJuu0U94ZcCuZKIQd/wrrh4qe0hyOBLQUtzHzq7UPn8FE8rXOXPuMf8A9d4VtfGbgBJwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/4024fb04f51fd8a89a7bb5bd3874fc12/ca1dc/1.png&apos; srcset=&apos;/static/4024fb04f51fd8a89a7bb5bd3874fc12/e7570/1.png 170w,
/static/4024fb04f51fd8a89a7bb5bd3874fc12/f46e7/1.png 340w,
/static/4024fb04f51fd8a89a7bb5bd3874fc12/ca1dc/1.png 680w,
/static/4024fb04f51fd8a89a7bb5bd3874fc12/02d09/1.png 1020w,
/static/4024fb04f51fd8a89a7bb5bd3874fc12/9d567/1.png 1360w,
/static/4024fb04f51fd8a89a7bb5bd3874fc12/84e61/1.png 1566w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;피드 태그를 가져오기 위해 leftJoin과 fetchJoin을 한 것을 확인할 수 있다.
그리고 요청받은 사이즈만큼 피드를 조회하기 위해 limit 구문을 추가했다.&lt;/p&gt;
&lt;p&gt;그런데 실제 쿼리가 나간 것을 확인해보니 limit 구문이 적용이 되지 않고 있었다. &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;select
    &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
from
    feed f1_0 
    &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
left join
    feed_tag v1_0 
        on f1_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;v1_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feed_id 
where
    f1_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; 
order by
    f1_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;created_at desc&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;이유&lt;/h2&gt;
&lt;p&gt;그 이유는 fetchJoin과 limit을 함께 써서 그렇다.
N쪽의 테이블에서 몇 개의 데이터를 가져와야하는지 알 수 없어서 테이블 정보를 모두 가져올 수 밖에 없다는 것이다.&lt;/p&gt;
&lt;p&gt;아래 그림과 같이 피드가 존재한다고 하자.
피드 3개를 가져오기 위해 limit 3을 걸었다.
우선 피드 태그에 fetchJoin을 붙이지 않으면 어떤 결과가 나올까?&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b78b3a60ee2fb26a93604961876195c9/f03ba/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 46.470588235294116%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA+0lEQVR42nWSyY6EMAxEw75KHBCIXYgTCG78/7d59DJyK013Hwxx2a5UJTFRFEmWZZKmqY04jgUsSZIXRmgPeFVV0jSN/bs9zBoWQRCI53lijJGiKKQsyxdGsIYoDEObT9Mk933Luq4Wp04tz3MxAL7vWzJiGAY5jsOqVAwScgbJ+76X67pknmfReWq4MHxoVtBVpcHurkKXUB3+VDiOo2zb9n8ejkLyJ+GyLJ+EqlDVcdBt275ZoRlCtdx1nZznaRUy/2b5eSl1XVsFqvDbpVCHkMv5UPgk5DlgBQIlRIGeMxgO9n23hPRpj1UIs/sO1f7zHT6DGXeOgOsPjwTHGy/AILwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/b78b3a60ee2fb26a93604961876195c9/ca1dc/2.png&apos; srcset=&apos;/static/b78b3a60ee2fb26a93604961876195c9/e7570/2.png 170w,
/static/b78b3a60ee2fb26a93604961876195c9/f46e7/2.png 340w,
/static/b78b3a60ee2fb26a93604961876195c9/ca1dc/2.png 680w,
/static/b78b3a60ee2fb26a93604961876195c9/02d09/2.png 1020w,
/static/b78b3a60ee2fb26a93604961876195c9/f03ba/2.png 1248w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;결과는 피드1 밖에 가져오지 못한다.&lt;/p&gt;
&lt;p&gt;그 이유는 피드와 피드 태그를 Join 했기 때문에,&lt;/p&gt;
&lt;p&gt;(피드1, 피드 태그1-1)
(피드1, 피드 태그1-2)
(피드1, 피드 태그1-3) &lt;/p&gt;
&lt;p&gt;이렇게 3개의 데이터가 조회되었고, 엔티티로 변환되면서 피드 1개만 반환되는 것이다.&lt;/p&gt;
&lt;p&gt;그래서 이 문제를 해결하기 위해 fetchJoin을 사용해서 원하는대로 피드 3개를 받았지만,
앞서 말했던 limit 구문이 적용되지 않는 문제가 생겼다.&lt;/p&gt;
&lt;p&gt;피드 태그 테이블을 모두 가져와 메모리에 올려놓고 어플리케이션 단에서 limit 만큼 자르기 때문에,
요청을 한 번에 많이 보냈을 때 Out of Memory 문제가 생겼던 것이다.&lt;/p&gt;
&lt;h2&gt;해결방법&lt;/h2&gt;
&lt;p&gt;쿼리를 한 번만 보내서 모든 정보를 가져오자는 욕심을 버리고 쿼리를 두 번 날리도록 수정했다.
이때 @BatchSize라는 어노테이션을 붙여주었다.
이 어노테이션을 붙이면 지정한 size만큼 In절을 이용해 select할 수 있다.&lt;/p&gt;
&lt;p&gt;피드 엔티티의 피드 태그 필드에 @BatchSize를 적용했다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b9179d2b3033059e2ae168acac09efbc/853dd/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 24.11764705882353%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA9UlEQVR42k2QXW6DMBCEcxrSAsbG4H+TYAhK1fal9z/MdIBG6sOnkcfe2V1fck44SAF68DAuYr5nxBgRXICip02C1A5C2YNWnnT9ee4Oz+CtHXGp6hEdL5/3CXPOyFNGmRZstxWegc4GDCYgpgQfIr0IM7Ix/RgTLM/R8431uO6BZQkoJWJdPKbk4ZKDyx5y4HScyhqHhg1VO6MVLBwdevqqu0HLCVWjUdUDdTgn/PnY8L2t+FoLHiXh8xkwF64pGdZT+ww78gsC1TquZ1CLHYuGvDPkxREoRIRg510l/0RpMrCwM2Qv4rTK07NnGP3rX/FL//MLpjihoyiSBDUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/b9179d2b3033059e2ae168acac09efbc/ca1dc/3.png&apos; srcset=&apos;/static/b9179d2b3033059e2ae168acac09efbc/e7570/3.png 170w,
/static/b9179d2b3033059e2ae168acac09efbc/f46e7/3.png 340w,
/static/b9179d2b3033059e2ae168acac09efbc/ca1dc/3.png 680w,
/static/b9179d2b3033059e2ae168acac09efbc/02d09/3.png 1020w,
/static/b9179d2b3033059e2ae168acac09efbc/853dd/3.png 1328w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;피드를 조회할 때 20개보다 넘게 조회할 일이 없기 때문에 적절하게 사이즈를 20으로 지정해주었다.&lt;/p&gt;
&lt;p&gt;그럼 이제 피드 목록을 조회할 때 &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;피드를 지정된 사이즈 만큼 조회하는 쿼리 &lt;/li&gt;
&lt;li&gt;조회한 피드의 태그를 조회하는 쿼리 이렇게 두 번의 쿼리가 날아간다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;다음과 같이 쿼리가 제대로 나가는 것을 확인할 수 있었다.
기존 쿼리와 다른 점은 첫번째 쿼리에서는 피드 태그를 조회하지 않는다. 따라서 limit 절이 제대로 적용되었다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 542px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f6c0e521f366af1d5947478af85fae14/47f85/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 225.2941176470588%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAtCAYAAACu/EtoAAAACXBIWXMAABYlAAAWJQFJUiTwAAAD4UlEQVR42p2X61baUBCFfZO2VkXuBHIHQiJ30WrX6vu/ynS+CceGgkL4cVYSjTt7ZvbsGW8m+VryxU6iyVyyp610h4k0Or48dgO71j03rX4kvVEq02IjxXIn/dFY7ppDeWiPDPSxWxOQP+SmN0zFT3Jj2vfHdu5bQzu84947C+hu7pqedL1E0mwpQVrIWFPhBVNj3x7E0tFzCegHIC87QJhync23kuw/wKkNCBuAwvGTxBp6NdTaITvAeDoXP55Z5UfRzFJBHi8uyiHg2KodaMjJdGEygi2nfU0OqTShkkMk9LR6sRym2eJiXR4WRUWN0GEEU0Lv+xMZaLUf2leEjKhNNsoQpoi+FHdwXQ5hmM5WMlJm0XiuIb8a44n+7CodUpRJvpJQNTebP1v+GkinRm8fyYbqIuLZ4tmkQy4RfKNzpQ4BgOGkWFtfwxp2l/b0UchxhSHVbvZCrfLEPtbxYnv+CvSIIUUAkHCdsLlHk2MtzjDM6gAim5WBzNevCrixapNXqp9Mlwb6VdecNAc6hT8EsFi+qJzSa83B9XJh2oMZwABeahDHbmO9PJNMvZAcut6+qlOwfUBgmKmwETdFgrV3phiftF4pbOfYibn2s7EEmNY81zEnZTOMMmPFPcAAlkXamvuclU05KkuG1ZlCHrGuWmPUsfv56BlDmNjU0ytGca4zTs5lrIn26qgJIB1aDLZui6g96AHD8vHB20b/wwTqMDsIGdF+u+tqqLmsd+/WeoTsRulVDKfF+qDFnDycbd23ynMRoNtrmMNUlVwicu49ey5z6rzxwioPzJoKtSonZOfY/n5OY7jVoXUK/AOQ0O70ABxpDmGLXZFPG1R6LK8KXJg/vpoTxZPSQA5CJqxcHRodAljNI6JHizwzVrlv9oLKffl8AEh+AKXlmMmEjjYxBPJWXZgY+FVZ/S+vfci+dUo4LsypzV30AzYO1HmayhSXdqy4tgf/GJ7MIVsWoAib1vNjXHtpI8AZBQcHWmze9MO/7Hf0/EHIFIMq8lJU2QnZs91K7F52FXa5PbWm3BAu9Olb5jF5ROjkks6hHXt1ZwpfafVDA0t0dbP9kDVuLxM+djHgPbIJp7LcvpXLZfpknfH9oSe3KqHbxqDSfsPzm8PDvig/Gj0NLzORlmJemQOhTxZO8sszv/vSsb1woKqPZPuSy+o5U6BAQx3pvxW+VjfQHSfQa6gpGNo1X6jQu18A+snAjMBPtM1SXd86sZ5IWYR2eL5vobdEww80zwMt4ujTjfYmTD2tZl87oqMzJJXX940yLbSPA9ns5vL7z04llcvLm46EghHR0wL6nwL+BToOkr2nnoAsAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;4&apos; title=&apos;&apos; src=&apos;/static/f6c0e521f366af1d5947478af85fae14/47f85/4.png&apos; srcset=&apos;/static/f6c0e521f366af1d5947478af85fae14/e7570/4.png 170w,
/static/f6c0e521f366af1d5947478af85fae14/f46e7/4.png 340w,
/static/f6c0e521f366af1d5947478af85fae14/47f85/4.png 542w&apos; sizes=&apos;(max-width: 542px) 100vw, 542px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이후 두번째 쿼리에서는, 앞서 조회한 피드의 각각의 태그를 조회하는 데, 이때 In절을 이용하여 한번의 쿼리로 모든 피드의 태그를 조회하였다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;Hibernate:
    &lt;span class=&quot;token keyword&quot;&gt;select&lt;/span&gt;
        v1_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; feed_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        v1_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; v1_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; name
    &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt;
        feed_tag v1_0
    &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
        array_contains&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;v1_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feed_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;[정리]&lt;/h2&gt;
&lt;p&gt;1:N 연관관계에서 fetchJoin과 Limit 구문을 함께 쓰지 않도록 조심하자.
또 N+1 문제를 피하기 위해 무작정 fetchJoin을 붙이지말고 신중하게 하자.
실제 쿼리가 어떻게 나가는지도 꼭 확인하는 것이 필요할 것 같다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[Gradle] Jacoco를 활용하여 테스트 커버리지 설정하기]]></title><description><![CDATA[들어가며 이번 프로젝트 CI 플로우 과정 중에서 Jacoco를 활용하여 테스트 리포트를 발행하고, 커버리지를 체크하고 있다.
CI에 대한 글은 다음에 완전하게 구축된 이후에 작성하는 게 좋을 것 같아서, 오늘은 Jacoco…]]></description><link>https://hoonblog.netlify.app/use_Jacoco_to_set_up_test_coverage/</link><guid isPermaLink="false">https://hoonblog.netlify.app/use_Jacoco_to_set_up_test_coverage/</guid><pubDate>Thu, 21 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;이번 프로젝트 CI 플로우 과정 중에서 Jacoco를 활용하여 테스트 리포트를 발행하고, 커버리지를 체크하고 있다.
CI에 대한 글은 다음에 완전하게 구축된 이후에 작성하는 게 좋을 것 같아서, 오늘은 Jacoco에 대해서만 가볍게 짚고 넘어가고자 한다.&lt;/p&gt;
&lt;h2&gt;[Jacoco 설정하기]&lt;/h2&gt;
&lt;p&gt;Jacoco는, 테스트 코드 커버리지를 분석해주는 자바의 무료 라이브러리이다.Jacoco 플러그인에는 JacocoTestReport와 JacocoTestCoverageVerification Task 등이 존재한다.
(여기서는 이 2가지를 위주로 알아보도록 하자.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JacocoTestReport: 커버리지 결과를 리포트로 저장하는 역할&lt;/li&gt;
&lt;li&gt;JacocoTestCoverageVerification: 원하는 커버리지 기준을 만족하는 확인하는 Task&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;build.gradle 설정해주기 - JacocoTestReport&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;plugins &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id &lt;span class=&quot;token char&quot;&gt;&apos;jacoco&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

jacoco &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    toolVersion &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.8.10&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// https://www.jacoco.org/jacoco/trunk/doc/changes.html&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

jacocoTestReport &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dependsOn test
    reports &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        html&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;required &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        xml&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;required &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// QueryDSL QDomain 제외시키기&lt;/span&gt;
    def &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern in &lt;span class=&quot;token char&quot;&gt;&apos;**/QA&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;**/QZ&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    afterEvaluate &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        classDirectories&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;// 그 외의 매칭되는 클래스도 제외 대상&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;classDirectories&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;collect &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;fileTree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; excludes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;sidepair.domain.**.**&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Application*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Config*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Dto*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Request*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Response*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Interceptor*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Exception*&quot;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 리포트 생성 후 커버리지 체크&lt;/span&gt;
    finalizedBy jacocoTestCoverageVerification
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

jacocoTestCoverageVerification &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// QueryDSL QDomain 제외시키기&lt;/span&gt;
    def &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// qPattern = &quot;*.QA&quot;,&quot;*.QB&quot;,&quot;*.QC&quot;, ... &quot;*.QZ&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern in &lt;span class=&quot;token char&quot;&gt;&apos;*.QA&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;*.QZ&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    violationRules &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        rule &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// rule 활성화&lt;/span&gt;
            enabled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// 클래스 단위로 룰 체크&lt;/span&gt;
            element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;CLASS&apos;&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// 라인 커버리지를 최소 80% 만족&lt;/span&gt;
            limit &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;LINE&apos;&lt;/span&gt;
                value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &apos;&lt;span class=&quot;token constant&quot;&gt;COVEREDRATIO&lt;/span&gt;&apos;
                minimum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.80&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
						
            &lt;span class=&quot;token comment&quot;&gt;// 마찬가지로 제거 대상 지정&lt;/span&gt;
            excludes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;sidepair.domain.**.**&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Application*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Config*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Dto*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Request*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Response*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Interceptor*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Exception*&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

tasks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;named&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;test&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    outputs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dir snippetsDir
    &lt;span class=&quot;token function&quot;&gt;useJUnitPlatform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// test 수행 이후 리포트 생성&lt;/span&gt;
    finalizedBy jacocoTestReport
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;build.gradle 코드가 상당히 길기는 한데, 그렇게 어려운 내용은 아니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;plugins &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id &lt;span class=&quot;token char&quot;&gt;&apos;jacoco&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

jacoco &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    toolVersion &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.8.10&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// https://www.jacoco.org/jacoco/trunk/doc/changes.html&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;먼저, jacoco에 대한 플러그인을 설정해주는 부분이다.
현재 스냅샷 버전 제외 가장 최신 버전이 0.8.10이길래 이 버전으로 설치를 해주었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;jacocoTestReport &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    reports &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        html&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;required &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        xml&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;required &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// QueryDSL QDomain 제외시키기&lt;/span&gt;
    def &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern in &lt;span class=&quot;token char&quot;&gt;&apos;**/QA&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;**/QZ&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

tasks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;named&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;test&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// test 수행 이후 리포트 생성&lt;/span&gt;
    finalizedBy jacocoTestReport
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;jacoco에서 제공하는 테스트 리포트 발행을 위해 사용하는 부분이다.
test가 실행된 다음에 리포트를 발행해야 하기 때문에 finalizedBy을 통해서 test 실행 이후 동작하도록 만들었다.
finalizedBy는 A task의 성공과 실패에 상관없이 A가 끝나야 B가 실행되기 때문에 주의해서 사용하도록 하자.
(성공해야 실행되도록 하려면 dependsOn을 사용한다. 테스트가 실패하더라도 리포트를 발행해야 하기 때문에 여기서는 finalizedBy를 활용하였다.)&lt;/p&gt;
&lt;p&gt;이후, xml과 html에 모두에 대해서 리포트를 발행하도록 하였다.
사실 실제로는 html만 보는 경우가 많아서 꼭 xml까지 하지 않아도 된다고 생각한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// QueryDSL QDomain 제외시키기&lt;/span&gt;
    def &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern in &lt;span class=&quot;token char&quot;&gt;&apos;**/QA&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;**/QZ&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    afterEvaluate &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        classDirectories&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
								&lt;span class=&quot;token comment&quot;&gt;// 그 외의 매칭되는 클래스도 제외 대상&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;classDirectories&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;collect &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;fileTree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; excludes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;sidepair.domain.**.**&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Application*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Config*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Dto*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Request*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Response*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Interceptor*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string&quot;&gt;&quot;**/*Exception*&quot;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    finalizedBy jacocoTestCoverageVerification
    
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;프로젝트에서 현재 QueryDSL을 사용하고 있기 때문에 QueryDSL로 인해 생성된 QDomain이라는 것이 존재한다.
이 친구들이 테스트 커버리지에 들어가게 되면 50% 이하로 커버리지가 안 나오는 기이한 현상이 발생하기 때문에 qDomain은 패턴 매칭을 통해서 제외시켜주었다. 또한, Dto나 Config, Exception 같은 클래스는 테스트할 필요가 없다고 생각해서 제외해두었다.&lt;/p&gt;
&lt;p&gt;위 코드에서는 도메인과 인터셉터까지 있는데, 인터셉터는 추후 제거할까 생각 중이다. (충분히 테스트가 가능하니까)
도메인의 경우 테스트를 짜고 있기는 하지만, 나중에 도메인 객체를 전부 작성하게 되면 추가할까 생각 중이다.&lt;/p&gt;
&lt;p&gt;마지막으로 리포트를 발행하고 나면 커버리지를 설정할 수 있도록 태스크를 연결해두었다.&lt;/p&gt;
&lt;p&gt;이렇게 완성된 리포트의 경우 기본적으로 build/reports/jacoco/test/html 하위에 생성된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6b77e3c9ae16240285b84c847e6b85ee/984b6/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 77.64705882352942%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB0klEQVR42p2UW1PaUBSF/SetXEoghIQExlwPSSCkmhRMjEo749QHfbFT9c0/0P+9uvehwyiXAfqwHs4A36y19t6cBGYd6xL6Z/QfHxCVKRZhG7NRF2WoIfc78Pv1d6p9+J1r1HGyDRgYpxhV55imNsqgg5yUEezcVTCyGhCDBsJ/2gsUJFv/hJfKwkNuoiBnc6Ei8zq4Gev4nvRxFWm4jnXc0ns/0KrjwhsiFz18I2eXHFcCejI2O+Xo7Jq/uxUou6APOYpL79QZkCsNBcEYyI4klBwxbBaoUtzjBtAj2HSowKtC9J4r/PQUAqhwqEdbP4XzTvx2jdryTZ+vp1s55N7CMwXB2IRbCWRBF1O7tapAytzUTiBHjgdfEEd9qL9KWficOrL1mnS0vh679GEoHF1wfLMJtYiQJRZuY42maiA5ax0E3ZjyaNBE7KgQxQx5bCKnPlNHQUTD8o91uAQ2MHY0JPdvKFOHgC0aQO0g2FagIIeJ28af+zZuEn1jLY4HWhTZbuOx8lFEhjwteWqs/4vcxMTVcDV/wo8LH4uJhruvJu5SU9bhHwtcrhAt8OtvZNThpa/QqanynnkvvT2T3vlvM1yUSGknr6Mu3bMqb/hQ4F+J4AbSwLBMjwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/6b77e3c9ae16240285b84c847e6b85ee/984b6/1.png&apos; srcset=&apos;/static/6b77e3c9ae16240285b84c847e6b85ee/e7570/1.png 170w,
/static/6b77e3c9ae16240285b84c847e6b85ee/f46e7/1.png 340w,
/static/6b77e3c9ae16240285b84c847e6b85ee/984b6/1.png 630w&apos; sizes=&apos;(max-width: 630px) 100vw, 630px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;여기서 jacoco-resources 밑쪽에 있는 index.html이랑 tests 쪽의 index.html 둘로 나뉘어져 있는데, 나오는 정보가 살짝 다르다.
상위에 있는 index.html이 jacoco에 의해서 생성된 리포트이고, 아래의 index.html은 gradle에서 자동으로 만들어주는 것으로 알고 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ca4e7fe04bb190d4e73af49cafd3e2cd/6bde6/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 44.705882352941174%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABpUlEQVR42k2S2XKjMBBF/f9/luUhnrjiytgJZsdgwIAFCIHPtOQwFaq60NZX57Z6czgeCHyPZTHMs2HSE9M4oUeN1tqNh2FgmibGcXRrNuz4d9gzdn3jH0MO+4rAq1CqJ858tv4WLzsReh7bzyfKsuKSF4RRyPl8Jo7jR0QRWZaRpilJkpDnOZvgu2L7NrHbyc0jlMOZXbMj6ENqObCLnzioI0VT0MuFWj9o+r6X+Q1jVgejhBB+f154eTF8fGjKAvw6IVIBWizGSYR/PdGYlqquuF6vLvl2u4kbRdd1zuY6t3tCWPL+bgjCCdVBqgRfJTBDkifUQ4X9muYqAo0j7Hub3ItQ90PcSx0HV8uN9/fC66thv9fMGkLli2DK3dzxI59iKJxgURTUde1I2rb9T2iplBDaEjhC/6tk+8fgeRNdu1DrCiOvPRtDlqd0WrC5S3IrQo0jsYQ2HpYfhCulI3x+NrzJwyi1MM4Dy31xbRLGIaMZfyw3roZri1giW7u1jewFrm2SsOJ0mqUdZu4iZBetJStYXkpHYYTWiqxW14f53YPr/x9E4a6qnWvBtwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/ca4e7fe04bb190d4e73af49cafd3e2cd/ca1dc/2.png&apos; srcset=&apos;/static/ca4e7fe04bb190d4e73af49cafd3e2cd/e7570/2.png 170w,
/static/ca4e7fe04bb190d4e73af49cafd3e2cd/f46e7/2.png 340w,
/static/ca4e7fe04bb190d4e73af49cafd3e2cd/ca1dc/2.png 680w,
/static/ca4e7fe04bb190d4e73af49cafd3e2cd/02d09/2.png 1020w,
/static/ca4e7fe04bb190d4e73af49cafd3e2cd/9d567/2.png 1360w,
/static/ca4e7fe04bb190d4e73af49cafd3e2cd/6bde6/2.png 2100w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d20d18fa4bc7fe5ac79c4f236cef7b45/5feee/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 16.470588235294116%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAqUlEQVR42k2Oy07DMAAE8//fBVLhQsuxwuA4Ma6dRMSpX5WDhjQH4DCaXe1lGykld/quRwiB+TTUUskxcV084zKSciKlRAhxd4x//k/OmUZ8SM5HhW2/6C6KR/nAa3dCvL/xcj7w3D6hnUYphXMWYwzWXtC632x3tNb7Nk0TzTBODNoT50K4XTm5I8PNsXhP61v63GGCYZ5nvtd1f1Zr3d4G1q3fKaX85h+Vb+G1NLO3nwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/d20d18fa4bc7fe5ac79c4f236cef7b45/ca1dc/3.png&apos; srcset=&apos;/static/d20d18fa4bc7fe5ac79c4f236cef7b45/e7570/3.png 170w,
/static/d20d18fa4bc7fe5ac79c4f236cef7b45/f46e7/3.png 340w,
/static/d20d18fa4bc7fe5ac79c4f236cef7b45/ca1dc/3.png 680w,
/static/d20d18fa4bc7fe5ac79c4f236cef7b45/02d09/3.png 1020w,
/static/d20d18fa4bc7fe5ac79c4f236cef7b45/9d567/3.png 1360w,
/static/d20d18fa4bc7fe5ac79c4f236cef7b45/5feee/3.png 1970w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;상위의 index.html의 경우 위와 같이 어느 클래스에서 어떤 파일이 커버리지에 불충족하는지 나오게 된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/80dfeaf1b93ad58c8f4ade3e580bff86/6eb37/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 51.764705882352935%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABLklEQVR42qWSbWuDMBSF/f8/oB/6g8Y+r8gQVinry6xWjYmvSfTME6usMMegF2LClfvk3nPiWWshhECWZVBK4dnw+r53wDzPHXAYBjDHve1aGGPQmAZhFuKQHdCa9m8gP2VZQncdqqpCN+4Ea60RJzGkkDiKIzYvG2xft4hk5Ap54a9A/nBd3Tv7ueYi1Srs0z3CNESt6wmIFaDuB+y+YpylghjHrur6OQ073eEzOkEbC2MNaBKDozdN47oUhXBaUlOeGUVRuMVIRboY6jXjCEH8jnMxQnu93EQNCXXmtJMRhDLPoJFSSnemrtpMeY+u+bGPXfSGq4oegLOOBM1A5hiE0URGUiWwg30E+ld/FP5jKWAxx18Dcly+jlVgcAtwkZfFWRZz/afD2wjs78BvfYQMZc6CsrEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;4&apos; title=&apos;&apos; src=&apos;/static/80dfeaf1b93ad58c8f4ade3e580bff86/ca1dc/4.png&apos; srcset=&apos;/static/80dfeaf1b93ad58c8f4ade3e580bff86/e7570/4.png 170w,
/static/80dfeaf1b93ad58c8f4ade3e580bff86/f46e7/4.png 340w,
/static/80dfeaf1b93ad58c8f4ade3e580bff86/ca1dc/4.png 680w,
/static/80dfeaf1b93ad58c8f4ade3e580bff86/02d09/4.png 1020w,
/static/80dfeaf1b93ad58c8f4ade3e580bff86/9d567/4.png 1360w,
/static/80dfeaf1b93ad58c8f4ade3e580bff86/6eb37/4.png 2288w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;하위의 테스트 리포트는 위와 같이 걸린 시간이나 몇 개의 테스트가 성공하고 실패한지 확인할 수 있다.&lt;/p&gt;
&lt;h3&gt;build.gradle 설정해주기 - JacocoTestCoverageVerification&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;jacocoTestCoverageVerification &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// QueryDSL QDomain 제외시키기&lt;/span&gt;
    def &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// qPattern = &quot;*.QA&quot;,&quot;*.QB&quot;,&quot;*.QC&quot;, ... &quot;*.QZ&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern in &lt;span class=&quot;token char&quot;&gt;&apos;*.QA&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;*.QZ&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qPattern &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

   &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이번에는 커버리지에 대한 설정 부분이다.
마찬가지로 QDomain에 대해서는 측정할 필요가 없기 때문에 제거하도록 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
 
 violationRules &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        rule &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// rule 활성화&lt;/span&gt;
            enabled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// 클래스 단위로 룰 체크&lt;/span&gt;
            element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;CLASS&apos;&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// 라인 커버리지를 최소 80% 만족&lt;/span&gt;
            limit &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;LINE&apos;&lt;/span&gt;
                value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &apos;&lt;span class=&quot;token constant&quot;&gt;COVEREDRATIO&lt;/span&gt;&apos;
                minimum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.80&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
						
            &lt;span class=&quot;token comment&quot;&gt;// 마찬가지로 제거 대상 지정&lt;/span&gt;
            excludes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;sidepair.domain.**.**&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Application*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Config*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Dto*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Request*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Response*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Interceptor*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;**.*Exception*&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;QDomains&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;다음으로는 세부적인 커버리지 룰에 대해서 지정하는 부분이다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;element: 커버리지를 체크할 기준 정하기&lt;/li&gt;
&lt;li&gt;BUNDLE: 프로젝트의 모든 파일을 합친 것 (디폴트)&lt;/li&gt;
&lt;li&gt;CLASS: 클래스- GROUP: 논리적 번들 그룹&lt;/li&gt;
&lt;li&gt;METHOD: 메서드&lt;/li&gt;
&lt;li&gt;PACKAGE: 패키지&lt;/li&gt;
&lt;li&gt;SOURCEFILE: 소스 파일&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;나는 클래스 단위로 설정하기 위해 CLASS라고 지정해주었으며, 대부분 클래스 단위로 많이 보시는 것 같다.
좀 더 빡세게 하고 싶다면 METHOD로 해도 될 것 같은데, 그럼 너무 확인하기 힘들지 않을까 싶다.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;counter: limit을 통해 지정할 수 있으며, 커버리지 측정을 위한 최소 단위. 자바 바이트 코드의 실행을 기준으로 측정된다.&lt;/li&gt;
&lt;li&gt;BRANCH: 조건문 등의 분기 수&lt;/li&gt;
&lt;li&gt;CLASS: 클래스 수, 내부 메서드가 한 번이라도 실행되었다면 실행된 것으로 간주한다&lt;/li&gt;
&lt;li&gt;COMPLEXITY: 복잡도&lt;/li&gt;
&lt;li&gt;INSTRUCTION: Java 바이트코드 명령의 수 (디폴트)&lt;/li&gt;
&lt;li&gt;METHOD: 메서드 수, 메서드가 한 번이라도 실행되었다면 실행된 것으로 간주&lt;/li&gt;
&lt;li&gt;LINE: 빈 줄을 제외한 실제 코드의 라인 수, 라인이 한 번이라도 실행되었다면 실행된 것으로 간주&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;여기서 몇 퍼센트의 커버리지를 가졌을 때 빌드 실패를 터트릴 것인지 설정할 수 있다.
나는 조금 더 빡세게 하고 싶어서 LINE 기준으로 80%의 기준을 잡았다.
조금 더 널널하게 하고 싶다면 METHOD로 해도 될 것 같은데, 어차피 모든 분기점에 대해 테스트를 작성하려면 라인으로 하는 게 가장 나을 것 같다고 생각했다.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;value: limit을 통해 지정할 수 있으며, 측정한 커버리지를 어떠한 방식으로 보여줄 것인지 정한다.&lt;/li&gt;
&lt;li&gt;COVEREDCOUNT: 커버된 개수&lt;/li&gt;
&lt;li&gt;COVEREDRATIO: 커버된 비율, 0~1 사이의 수로 1이 100% (기본값)&lt;/li&gt;
&lt;li&gt;MISSEDCOUNT: 커버되지 않은 개수- MISSEDRATIO: 커버되지 않은 비율, 0~1 사이의 수로 1이 100%&lt;/li&gt;
&lt;li&gt;TOTALCOUNT: 전체 개수&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;task &lt;span class=&quot;token function&quot;&gt;copyDocument&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Copy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    dependsOn asciidoctor
    from &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;build/docs/asciidoc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    into &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src/main/resources/templates/docs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

build &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dependsOn copyDocument &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    asciidoctorExt &apos;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;spring&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;asciidoctor&apos; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    testImplementation &apos;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;spring&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;mockmvc&apos; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

bootJar &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dependsOn asciidoctor &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    from &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;${asciidoctor.outputDir}/html5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        into &apos;templates&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;docs&apos;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;커버되지 않은 비율을 보여주는 것보다 커버된 비율을 보여주는 게 도움이 될 것 같다고 생각했다.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;minimum: counter 값을 value에 맞게 표현하였을 때의 최소값, 이를 통해서 커버리지 판단의 성공 여부가 결정된다고 볼 수 있다.&lt;/li&gt;
&lt;li&gt;기본적으로 표기한 자리수만큼 value가 출력되기 때문에 90%의 커버리지를 원한다면 0.9가 아닌 0.90으로 입력해줘야 한다. 아니면 0.9로 입력하면 0.9x 값을 모두 0.9로 인식한다&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;나는 우선 80% 정도로 설정하였는데, 90%까지 올릴 생각은 있다.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;excludes: 커버리지 측정 시 제외할 클래스를 지정할 수 있다.&lt;/li&gt;
&lt;li&gt;패키지 레벨의 경로로 지정해야 하며, 경로에는 *와 ?을 사용할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;여기는 아까 테스트 리포트 발행했을 때의 경로랑 동일하게 지정해주면 된다.&lt;/p&gt;
&lt;h3&gt;실행해보기&lt;/h3&gt;
&lt;p&gt;Test 실행의 경우 ./gradlew test, ./gradlew clean build로도 실행이 가능하고, intellij를 사용하면 gradle 도구를 활용할 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a6e5f104d3724acbe5c87d69872335d4/683d4/5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABCklEQVR42qWQyXLCMBBE/TMpgi3JK7a8YDABgw0ptiSEhGNO+f/7i0wOHKHg8GrUM1JXayzpBqhpw6huCcIY5UU40rsbSwgXmZXkb0fq6Rydl48biiRH7w6MygrXH2Cb3gOGCqkL9PbAYt6wWu+Jjb7X9JJw+0GqMxzlm5TRAwkds0Ndkr6fGA//v+wIHyEvdPpWLNsX9NOIZLVk1tSkk5Ke5/DsiXM9n7s7gbwJyw4lT26PcT6kbhekLwVhETMoNbrKz/hZaEwd80BcxZIqpi8CJkVL2+xoVnteN5/Uiw1JVpGkFUGUm/1ECDW4iqWKb+z8i/Hsh9n6F1WeUMMTsutnRxyDMPNO38Ifyb0/3BEU7t8AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;5&apos; title=&apos;&apos; src=&apos;/static/a6e5f104d3724acbe5c87d69872335d4/ca1dc/5.png&apos; srcset=&apos;/static/a6e5f104d3724acbe5c87d69872335d4/e7570/5.png 170w,
/static/a6e5f104d3724acbe5c87d69872335d4/f46e7/5.png 340w,
/static/a6e5f104d3724acbe5c87d69872335d4/ca1dc/5.png 680w,
/static/a6e5f104d3724acbe5c87d69872335d4/02d09/5.png 1020w,
/static/a6e5f104d3724acbe5c87d69872335d4/683d4/5.png 1174w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;만약 minimum값에 0. 90을 입력하고 결과를 보면, 아래와 같이 커버리지를 넘지 못했을 때 빌드 실패가 발생하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b17b24cbf957dac974195dda59ec351d/e05f4/6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 12.352941176470589%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAZElEQVR42jWMSw6AIBBDuQqfEQaiGD+48f7XqgXi4qXNdFrTRPHGgkcyqo84QsI1UJzUm3ljXumrJGS3QJ2gdLWCRJR+ZVdsgIk89NHdz+eJzGdq9gs2Dm1jUFFY/Ec6w5O/9wF3Zzp3zwc9PwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;6&apos; title=&apos;&apos; src=&apos;/static/b17b24cbf957dac974195dda59ec351d/ca1dc/6.png&apos; srcset=&apos;/static/b17b24cbf957dac974195dda59ec351d/e7570/6.png 170w,
/static/b17b24cbf957dac974195dda59ec351d/f46e7/6.png 340w,
/static/b17b24cbf957dac974195dda59ec351d/ca1dc/6.png 680w,
/static/b17b24cbf957dac974195dda59ec351d/02d09/6.png 1020w,
/static/b17b24cbf957dac974195dda59ec351d/9d567/6.png 1360w,
/static/b17b24cbf957dac974195dda59ec351d/e05f4/6.png 1922w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이때는 테스트 리포트 보면서 어디가 부족한지 보고 확인하면서 진행하면 된다.&lt;/p&gt;
&lt;p&gt;참고로, Lombok의 어노테이션에 대한 코드 커버리지가 0%로 나오는 문제를 방지하기 위해서 lombok.config를 추가로 설정해주자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;lombok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;addLombokGeneratedAnnotation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 514px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ca8a1b135c22bb39b48c82f73f98e3f2/1cbe9/7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 140.58823529411765%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAcCAYAAABh2p9gAAAACXBIWXMAAAsTAAALEwEAmpwYAAADuklEQVR42pWVaY/TVhSG8zcqtQWKOovjeI23eI2TjJ19sk3IwJQOKsMgsbRUSKj9UlXt7356bEAqKkXJh0eRfc99c+497zluqLqNG3YZJyqvr8cMZ2uWmx2L9QMm8xXnqy03ty+5vLpmtrjg6e2L+v1JU6ftdkiyHmHSpRNlBGFKw9RVLFMncRU2k5g8jel3E7JEgqOAQS9jPhtz1s8ZFn3m0zHdNEJvKbi2ScdrE3wgDFwaqf0dsXmXsqMSRCbmLz+zmPd4sh3x/HrDehThNb8i1L8l1L4haH1NZNyh2pdY9+q9/6bhGKe0Bd9ScR0df1hIlh0GWUieBESeSRXjGJKR+R6non73XxpKy+RENXDaPnpecGf3Aj8+44fHT+gVY44VjSpmXxrNlkGFpltotosul2yKuOMGGJbDx/V9kQwNyVAq5viYccrq7z/JyhG2PFfvq/VDaPjmMb5xROg0SYRF5tPvGOS+Su6p1OsH0Eisqsr3GIQqpXfCX7sFP01DLvsqi/hUKnqXKmZfGpqm0Wq1aFsWuutxdL4iSBK6WZezosBxnHq9ituHusqnUmXb9mh6Edbta0bLC+bnay52j3CDuO6KpmbtX2VFLt+0Hex2R7w4IE770kYxRycKTVlTNXP/Kn8UtNqe2ES8GI7JBiM6YcL3x00Rfc9BghUnSkuydLl59pwwzjhfbmQYrBlNzimGU/nTAwWV2twmZTGSI3cpyqEwIk0zwjBCUdTDBKu7UkyH+8sfMfMFTm+LnS1wBw/wyys65cPDBZtGGyUt0JwYM+hh+F2ssMAI+mKp5FBBjabd4Xj9ljQIWaYJ627GQjw5jWMWacqgE9XtqO6foYMSj7EtV4ang+94BELo+mJ8B10GyMEZ3p/eUCYpS+mUcylIxeXgDMuwxeDaF7P7VLBCDOzZPcnGw/c7RFGKK7+GiLX2yO4TwdOWhqV77NrXTCdrNruHbHdXtR81KVZlblU7pCiCKr0YGz08N5KvWCJftBwviKQNk5r9BavGl+OaesimfcN4tGG5fch6e8VotmK+qj6pG44U8apmS/z/02jqDlr2lFZ2i50/JR/vSGavyFdvyZe/kp2/IZy8oid2Ki7eYeS3tNJnsufzfBC8odV9jtW7IR8+prd8w+jyNyaPfqfYvqN48I5SWD35A7d8iVoJdm8/S31kVassYeB1MqbLSwblrD5iOV7KgNiS5iWD4RzTCes4VW9/4cgfh8OHmTiezMjyPuVwUjMaV88DmThjKVDIqXjxS0X5B9J8mQTFOwzwAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;7&apos; title=&apos;&apos; src=&apos;/static/ca8a1b135c22bb39b48c82f73f98e3f2/1cbe9/7.png&apos; srcset=&apos;/static/ca8a1b135c22bb39b48c82f73f98e3f2/e7570/7.png 170w,
/static/ca8a1b135c22bb39b48c82f73f98e3f2/f46e7/7.png 340w,
/static/ca8a1b135c22bb39b48c82f73f98e3f2/1cbe9/7.png 514w&apos; sizes=&apos;(max-width: 514px) 100vw, 514px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;위와 같이 프로젝트의 최상단 경로에 적용해두어야 적용이 된다.
참고로 메서드 단위로 측정을 패스하는 게 없을 때는 커버리지 측정을 원하지 않는 클래스라면 패키지 단위로 묶어두는 게 좋다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[Spring] Rest-docs 연동하기]]></title><description><![CDATA[들어가며 지금은 솔로 프로젝트이지만 다른 프로젝트를 잔행할 때 프론트 팀원과 협업하게 될 경우 필요할것 같았고, 과거 Swagger…]]></description><link>https://hoonblog.netlify.app/rest-docs-connection/</link><guid isPermaLink="false">https://hoonblog.netlify.app/rest-docs-connection/</guid><pubDate>Wed, 20 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;지금은 솔로 프로젝트이지만 다른 프로젝트를 잔행할 때 프론트 팀원과 협업하게 될 경우 필요할것 같았고, 과거 Swagger를 구축해본 경험이 있기도 해서 개인으로 욕심으로 한 번 직접 구축해보고 싶다는 생각이 들어 프로젝트 하는김에 함께 진행하게 되었다.&lt;/p&gt;
&lt;h2&gt;[Rest-docs는?]&lt;/h2&gt;
&lt;p&gt;Spring Rest Docs는 Restful 서비스에 대해 정확하고 읽기 쉬운 문서를 생성할 때 도움을 주는 문서 자동화 도구이다.
흔히 백엔드, 프론트엔드가 협업할 때 프론트엔드는 API endPoint를 알고 있어야 해당 API로 요청을 보내서 response를 받아 처리한다. 만약 백엔드 개발자가 API 문서를 수정했다면 프론트엔드 개발자한테 어떻게 알려야 할까?
직접 메신저로 &apos;요구사항이 변경되었어요&apos; 라고 말할 수도 있겠지만, 이는 매우 번거롭다.
만약 프론트엔드 개발자가 당장 수정해야 하는 hotfix 요구사항임에도 메신저를 읽지 못했다면? 혹은, 원하는 시간에 서로 소통할 수 없다면? 하나의 정형화된 문서를 통해서 관리하는 게 훨씬 쉬울 것이다.
Swagger를 사용하는 경우도 있고, Rest docs를 사용하는 경우도 있을 텐데 각각의 장단점이 뚜렷하다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6809bb258ba08649bc5d2c002e011fb8/78d47/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 47.05882352941176%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABYklEQVR42qXRS0sjQRDA8fmeuu6XEAQ/wF5c9ix48CCsBzeCGtiToogKezCLbhI1Ms4j0zM6j+4ZJ6+J8W8nWSQqomI1PwqKoqCrjPXKV7Ybs+xdzbNVn6Zc+8JmdeqZaXbr39g/+8H++QJ/zEWqXoma+EXdX6NcmWP1aGbUa9wEEealg2v52KbAc0M+E0aSBIjAQaWSXr9LcdfT5fv/bzDh9Xjsvu9jnJs1TqsVhGXi2zZZFKHCEHV9TS4T7jrtJ4pWTktJOlk6kRXdNIW+HrhxuMzv400a1RMct0GqAuLYQyYClfgoGbwgdV1Kf5SHPW5wgfAuQA82xM/vuLsl/KbDjWPSUyFFGmvRSO8tuj8XV7SFBVmGsbqyw9b2X2zX5V+9QRAqZNYhSdvvIjXHi8fHHA5cKp+ydnBJ0zSxLI84yog+yBaSphuNvzzQS+3r5XalvrI2uL2FdutjWlqeQ1HwAHIcnI3D8oygAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/6809bb258ba08649bc5d2c002e011fb8/ca1dc/1.png&apos; srcset=&apos;/static/6809bb258ba08649bc5d2c002e011fb8/e7570/1.png 170w,
/static/6809bb258ba08649bc5d2c002e011fb8/f46e7/1.png 340w,
/static/6809bb258ba08649bc5d2c002e011fb8/ca1dc/1.png 680w,
/static/6809bb258ba08649bc5d2c002e011fb8/78d47/1.png 800w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Swagger의 경우 테스트 코드 작성에 부담이 없지만, 프로덕션 코드 자체에 문서에 대한 설정 내용이 어노테이션으로 들어가기 때문에 이 자체가 부담이 될 수 있다. Swagger에서 Rest docs로 전환해야 한다면 프로덕션 코드 자체를 전부 바꿔야 하기 때문이다.
하지만, Rest-docs보다는 비교적 적용하기가 쉬우며, 문서 자체는 우리가 직접 구축할 필요없이 알아서 만들어주고, 직접 테스트를 해볼 수 있는 화면을 제공하기 때문에 프론트엔드 개발자 입장에서는 조금 더 편할 수도 있다.&lt;/p&gt;
&lt;p&gt;반면에 Rest-docs의 경우 테스트 코드를 기반으로 하기 때문에 프로덕션 코드에는 영향을 끼치지 않는다.
이 말은 곧, 테스트 코드가 정말 꼼꼼하게 짜여 있어야 한다는 것이다. 성공했을 때, 예외가 발생했을 때 등등...
response 값이 변화하여 내려가는 경우에는 웬만하면 테스트 코드를 작성해야 한다. (그렇기 때문에 RestAssured보다 덜 무거운 MockMvc를 활용하는 게 더 낫다고 판단한 점도 있다.)
또한, 스웨거에 비해 구축이 어려운 편이다. 문서 구축 자체는 빌드된 adoc 파일을 직접 조립해야 하고, 프론트엔드 개발자가 직접 테스트해볼 수도 없다. 하지만, 직접 구축하기 때문에 문서 내부에 어떤 내용이 들어갈지 조금 더 세분화하여 개발자가 작성할 수 있다.&lt;/p&gt;
&lt;p&gt;개인적으로 규모가 작다면 swagger를 사용해볼만 하다고 생각하지만, 프로덕션 코드 자체를 수정하는 게 찝찝하기 때문에 rest-docs를 조금 더 선호하는 편이다. 한 번 적용해두면 그뒤부터 응용은 쉽기 때문에 처음 러닝커브만 조금 견디면 된다.&lt;/p&gt;
&lt;h2&gt;[SetUp - build.gradle]&lt;/h2&gt;
&lt;p&gt;그전에, Rest Docs의 경우 기본적으로 &apos;Asciidoctor&apos;라는 친구를 사용하는데, 이 친구는 일반 텍스트를 처리하면서 HTML 형태로 만들어주는 친구다. 이 친구의 개념 자체가 중요한 건 아니지만, HTML로 문서를 생성하기 위한 일종의 전처리 도구라고 생각하자.
또한, 각각의 테스트 코드가 성공하면 &apos;snippet&apos;이라는 친구가 생성되는데, 이러한 스니펫들을 조립하여 문서를 생성한다고 생각하자.&lt;/p&gt;
&lt;p&gt;먼저, build.gradle에 다음과 같은 내용을 추가해야 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;plugins &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	id &apos;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;asciidoctor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jvm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;convert&apos; version &lt;span class=&quot;token char&quot;&gt;&apos;3.3.2&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
configurations &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    asciidoctorExt
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ext &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    snippetsDir &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&apos;build&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;generated&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;snippets&apos;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
test &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    outputs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dir snippetsDir
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

asciidoctor &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    inputs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dir snippetsDir
    configurations &apos;asciidoctorExt&apos;
    dependsOn test

    sources &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;**/index.adoc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;baseDirFollowsSourceFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

asciidoctor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;doFirst &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    delete &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&apos;src&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;resources&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;templates&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;docs&apos;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

task &lt;span class=&quot;token function&quot;&gt;copyDocument&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Copy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dependsOn asciidoctor
    from &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;build/docs/asciidoc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    into &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src/main/resources/templates/docs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

build &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dependsOn copyDocument
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    asciidoctorExt &apos;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;spring&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;asciidoctor&apos;
    testImplementation &apos;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;spring&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;mockmvc&apos;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

bootJar &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dependsOn asciidoctor
    from &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;${asciidoctor.outputDir}/html5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        into &apos;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;docs&apos;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;생각보다 설정해줄 것이 굉장히 많기 때문에 조금씩 나눠서 보도록 하자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;plugins &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id &lt;span class=&quot;token string&quot;&gt;&quot;org.asciidoctor.jvm.convert&quot;&lt;/span&gt; version &lt;span class=&quot;token string&quot;&gt;&quot;3.3.2&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

configurations &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    asciidoctorExt &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ext &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    snippetsDir &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&apos;build&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;generated&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;snippets&apos;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

tasks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;named&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;test&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    outputs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dir snippetsDir &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Asciidoctor 플러그인을 적용한다.&lt;/li&gt;
&lt;li&gt;asciidoctorExt를 프로젝트의 configuration에 추가한다.
asciidoctorExt는 Asciidoctor를 사용하여 문서를 생성하고 포맷하는 데 사용하는 플러그인인데, 이를 이용하여 HTML 형식으로 출력할 수 있도록 만든다고 생각하면 된다.&lt;/li&gt;
&lt;li&gt;생성된 스니펫들을 어느 위치에 저장할 것인지 지정하는 것이다. (디폴트로 build 폴더 밑에 생성하는 편)&lt;/li&gt;
&lt;li&gt;저장한 스니펫 경로가 테스트 결과로 생성되는 디렉터리에 추가되도록 설정하는 것이다.
테스트가 실행될 때 스니펫이 생성되면, 해당 디렉터리에 저장되는 것이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;asciidoctor &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    inputs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dir snippetsDir &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    configurations &apos;asciidoctorExt&apos; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    dependsOn test &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    sources &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;**/index.adoc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;baseDirFollowsSourceFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

asciidoctor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;doFirst &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    delete &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&apos;src&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;resources&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;templates&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;docs&apos;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;asciidoctor가 할 일을 정의하는 부분이다.
이전에 설정한 스니펫 저장 경로를 입력 디렉터리로 만들어서, asciidoctor가 문서를 생성할 때 어디를 참조할지 지정하는 것이다.&lt;/li&gt;
&lt;li&gt;ext에서 구성한 asciidoctorExt를 구성 파일로 사용하도록 만드는 것이다.&lt;/li&gt;
&lt;li&gt;문서가 생성되기 전에 테스트가 실행될 수 있도록, test에 종속적이도록 만든다. (test 실행 -&gt; 문서 생성 느낌!)&lt;/li&gt;
&lt;li&gt;rest-docs 문서의 경우, .adoc 파일을 바탕으로 생성하게 되는데 이때 source를 지정하게 되면 특정 adoc만 HTML로 만든다.
만약 모든 adoc에 대해 각각 html을 만들고 싶다면 해당 옵션은 제거해도 된다.&lt;/li&gt;
&lt;li&gt;특정 .adoc에 다른 adoc을 include 하고 싶을 때 경로를 baseDir로 맞춰주는 역할이다.
나 같은 경우 index.adoc으로 세부 adoc을 로드하도록 만들었기 때문에 이 옵션을 활성화해주었다.&lt;/li&gt;
&lt;li&gt;static.docs 파일을 초기화하고 다시 만들도록 설정하는 것이다.
기본적으로는 static 하위에 두는 경우가 많은데, 미션에서 타임리프를 사용하다 보니 templates 폴더 하위로 설정하였다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;task &lt;span class=&quot;token function&quot;&gt;copyDocument&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Copy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    dependsOn asciidoctor
    from &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;build/docs/asciidoc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    into &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src/main/resources/templates/docs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

build &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dependsOn copyDocument &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    asciidoctorExt &apos;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;spring&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;asciidoctor&apos; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    testImplementation &apos;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;spring&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;restdocs&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;mockmvc&apos; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

bootJar &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dependsOn asciidoctor &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    from &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;${asciidoctor.outputDir}/html5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        into &apos;templates&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;docs&apos;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;11&quot;&gt;
&lt;li&gt;asciidoctor 작업한 이후 (dependsOn), build/docs/asciidoc을 보면 상단에서 설정해준 source 옵션에 따라 html이 생기게 된다. 나 같은 경우 프로덕션 코드에서 html에 접근할 수 있도록 하기 위해서 resources/templates/docs에 복사를 진행하였다.&lt;/li&gt;
&lt;li&gt;빌드 작업이 copyDocument 이후에 진행되도록 설정한다.&lt;/li&gt;
&lt;li&gt;asciidoctorExt configuration을 사용하여 restdocs-asciidoctor 라이브러리에 대한 의존성을 설정한다.
이렇게 하면 .adoc 파일에서 빌드, 생성된 스니펫을 가리키도록 스니펫 속성이 자동으로 구성된다.&lt;/li&gt;
&lt;li&gt;MockMVC를 활용하여 rest-docs를 구성할 때 사용한다. (Rest-Assured를 사용하면 spring-restdocs-restassured 사용)&lt;/li&gt;
&lt;li&gt;생성된 문서를 jar 파일에 패키징해서 정적 컨텐츠로 제공할 때 사용하는 것이다.
asciidoctor에 종속적이도록 만들어서, jar 파일을 빌드하기 전에 문서가 생성되었는지 체크한다.
이렇게 되면 jar 파일이 빌드되기 전에 문서가 생성되고, 생성된 문서는 jar 파일에 포함된다.
asciidoctor 진행 이후 문서를 templates/docs로 이동시킨다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;결과적으로 ./gradlew clean build를 진행하게 되면 test -&gt; asciidoctor -&gt; copyDocument -&gt; build 순으로 세팅이 진행된다.&lt;/h4&gt;
&lt;h2&gt;코드에 적용하기 (Junit5 기준)&lt;/h2&gt;
&lt;p&gt;우선, 테스트할 대상 클래스에 다음과 같은 셋업 작업을 진행해준다.
controller가 여러 개라면 공통적으로 사용할 부분은 빼는 것이 좋기 때문에, 나는 별도의 helper 클래스를 생성해두었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@ExtendWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;RestDocumentationExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RestDocsHelper&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MockMvc&lt;/span&gt; mockMvc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RestDocumentationResultHandler&lt;/span&gt; documentationResultHandler&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@BeforeEach&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setUp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WebApplicationContext&lt;/span&gt; webApplicationContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
               &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RestDocumentationContextProvider&lt;/span&gt; restDocumentationContextProvider&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentationResultHandler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MockMvcRestDocumentation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;{class-name}/{method-name}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;Preprocessors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preprocessRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Preprocessors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prettyPrint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;Preprocessors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preprocessResponse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Preprocessors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prettyPrint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mockMvc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MockMvcBuilders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;webAppContextSetup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;webApplicationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CharacterEncodingFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;alwaysDo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcResultHandlers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;alwaysDo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;documentationResultHandler&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;documentationConfiguration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;restDocumentationContextProvider&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Junit5에서 사용할 수 있으며, Spring Rest Docs의 RestDocumentationExtension 클래스를 사용하여 테스트를 확장시키는 것이다. 어렵게 생각할 필요없이, API 문서를 생성하기 위해 환경을 설정한다고 보면 된다.&lt;/li&gt;
&lt;li&gt;문서의 세부 경로를 설정해주는 부분이다. build/generated-snippets 패키지 밑에, class-name 패키지, 그리고 method-name 패키지 하단에 각각의 스니펫이 생성되도록 만드는 설정이다.&lt;/li&gt;
&lt;li&gt;사실 이 부분에 나중에 배포될 때를 대비하여 프로토콜 정보나 host 정보도 지정해줄 수 있다. (Preprocessors.modifyUris 활용)&lt;/li&gt;
&lt;li&gt;request, response에 대해서 전처리 작업을 해주는 것인데 요청, 응답에 대해 읽기 쉽도록 만들어준다.&lt;/li&gt;
&lt;li&gt;각각의 테스트 메서드가 실행되기 전에 공통적으로 실행할 작업을 정의한다.
mockMvc에 대해서 설정하는 것을 볼 수 있는데, 이를 통해 Spring REST docs에서 생성된 컨텍스트를 사용하여 API를 테스트할 수 있도록 만들어주는 전초 작업이라고 볼 수 있다.&lt;/li&gt;
&lt;li&gt;문서 생성 시 한글이 깨질 수 있기 때문에 이를 위해 인코딩 형식을 지정해주는 부분이다.&lt;/li&gt;
&lt;li&gt;처리한 내용에 대해 항상 로깅 작업을 수행하도록 print를 해주는 부분이다.&lt;/li&gt;
&lt;li&gt;위에서 설정한 정보들을 항상 적용하도록 만드는 것이다.&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title><![CDATA[[Redis] Redis Cache를 활용한 성능 개선기 (2)]]></title><description><![CDATA[Spring에서 Redis Cache 도입 캐시 전략을 선택했으니 이제 프로젝트에 진행할 차례이다. Redis는 다양한 언어를 지원하고 여러 프레임워크에서 Redis를 위한 추상화가 잘 되어있어서 도입하기 굉장히 편하다. 이번 프로젝트는 Spring…]]></description><link>https://hoonblog.netlify.app/performance-improvement-with-redis-cache-2/</link><guid isPermaLink="false">https://hoonblog.netlify.app/performance-improvement-with-redis-cache-2/</guid><pubDate>Sat, 16 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[Spring에서 Redis Cache 도입]&lt;/h2&gt;
&lt;p&gt;캐시 전략을 선택했으니 이제 프로젝트에 진행할 차례이다. Redis는 다양한 언어를 지원하고 여러 프레임워크에서 Redis를 위한 추상화가 잘 되어있어서 도입하기 굉장히 편하다. 이번 프로젝트는 Spring boot 3.1 버젼 Java 17 버젼이로 이루어져 있으니 이 기준인 점 참고 바란다.&lt;/p&gt;
&lt;h3&gt;[Redis 설정]&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8ca1786d5101053f713372ebb4220714/bd833/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 43.529411764705884%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABR0lEQVR42n2SWXLDIBBEfZBYAiE2LRjQZlfuf65OQ8UVO3by0TWDSjSvB05htAhTwCUu0G5G5yMUZbSG9yP8MMO6Ab12MNZXWTdybdC08kWnXmns2479uCGvB7brJ3JekVPCcfvEsq6w1kL1ppr22kKqHkKq94Ztp+BIUQgTjVJaEGNGjiu2eMD5Adq4KmNJynpuBT7OLc6NeDUUQkLzRMMYJZqx3FziGc/vmtU+RC3mrN+940iE6J4Npeww0CQUKhJGEl7Yh5Thp7nOsZgN41zlhwm2znaqa8NxNO0P6anhCQW9RN72W53lQYWYSD1UmjtdNStk32nuiVrxGJmEptc8LWAOCdMcqYBwSVTGyBfQMbrs+qpyGfe+rjv161JI2LIpUbf9yotZkJeN2mudGFtyU0nxl54MGyl5a7I+B6XUyw/vNv2nL+/eBLUmBa/9AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/8ca1786d5101053f713372ebb4220714/ca1dc/1.png&apos; srcset=&apos;/static/8ca1786d5101053f713372ebb4220714/e7570/1.png 170w,
/static/8ca1786d5101053f713372ebb4220714/f46e7/1.png 340w,
/static/8ca1786d5101053f713372ebb4220714/ca1dc/1.png 680w,
/static/8ca1786d5101053f713372ebb4220714/02d09/1.png 1020w,
/static/8ca1786d5101053f713372ebb4220714/9d567/1.png 1360w,
/static/8ca1786d5101053f713372ebb4220714/bd833/1.png 1990w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;redis를 통해 캐시를 하려면 몇몇 설정들이 필요하다. 위의 설정을 하나씩 살펴보자.&lt;/p&gt;
&lt;p&gt;로컬 캐싱의 경우, 객체 자체가 어플리케이션 메모리에 보관되기 때문에 타입 정보가 그대로 유지되고, 객체의 상태가 변하지 않는다. 그래서 직렬화, 역직렬화가 필요하지 않거나 필요한 경우에도 객체의 값이 변하는 걱정은 하지않아도 된다.&lt;/p&gt;
&lt;p&gt;하지만 글로벌 캐싱(redis)의 경우, 데이터를 문자열이나 JSON 같은 포맷으로 저장한다. 어플리케이션에서는 이 데이터가 어떤 객체인지 정확하게 모르고, 역직렬화(json -&gt; 객체) 시 타입이 변환되거나 값이 변할 가능성이 생긴다.&lt;/p&gt;
&lt;p&gt;그래서 redis를 직렬화, 역직렬화를 위해서 type을 정확하게 알려주는 Custom ObjectMapper를 만들어야할 필요가 있다.
Custom ObjectMapper에 대해서 하나씩 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a8b15466ef70f154d4d7b3dd168af07b/171ca/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 24.705882352941178%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA60lEQVR42kWQ6ZKDIBCE8yCrch8ieCRiNKb2/Z+qd8DU5sdXDUXR0z03aw2889AmEB4d12i5QcMMGFfgXFYtSGXBhYaQ5gvdGZNoO1G5aaWxxIicdzz3N4Z5Q3qcSOsbIUTcpxnr84VlWWBdD6UdjA0V6wKcH8Cl+ho2HceQZjyPE2s+sNHnnc5bzlgfGa/jF/t+ItDQYmDcZWRsj05I/DQMTcuJj2FLcTnVKdPTeCcWxDTRkAkxzhj7GdGnmqys5KKvKpX5X0HRj6GApsiODK8qvpprbetZkqr6XpINtaLz8aJWDujDWLVjAn8Qi5NDqZ9axQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/a8b15466ef70f154d4d7b3dd168af07b/ca1dc/2.png&apos; srcset=&apos;/static/a8b15466ef70f154d4d7b3dd168af07b/e7570/2.png 170w,
/static/a8b15466ef70f154d4d7b3dd168af07b/f46e7/2.png 340w,
/static/a8b15466ef70f154d4d7b3dd168af07b/ca1dc/2.png 680w,
/static/a8b15466ef70f154d4d7b3dd168af07b/02d09/2.png 1020w,
/static/a8b15466ef70f154d4d7b3dd168af07b/9d567/2.png 1360w,
/static/a8b15466ef70f154d4d7b3dd168af07b/171ca/2.png 1684w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerModule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JavaTimeModule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 설정은 Java8의 날짜와 시간 API를 지원하기 위해 등록해야한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;activateDefaultTyping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPolymorphicTypeValidator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ObjectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DefaultTyping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;EVERYTHING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 설정은 보안 상 안전하지 않은 타입의 역직렬화를 방지하는 목적이다. 즉, 외부에서 들어오는 데이터를 역직렬화하여 어플리케이션으로 가져왔을때 이 객체가 안전한 객체인지 확인하고 역직렬화를 진행하도록 하는 것이다. 예를 들어 위험한 명령어(ex -&gt; DB 조작, 파일 삭제 등)가 포함 되어있는 객체가 어플리케이션 내로 들어오면 큰일 나기 때문에 이를 방지하는 것이다.
activateDefaultTyping를 통해서 역직렬화할 객체의 화이트리스트를 정의할 수 있고, DefaultTyping을 설정하여 보안을 강화할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;하지만 위 설정은 잘못 되어있다.&lt;/em&gt;&lt;/strong&gt; 위 설정은 모든 객체에 대해서 역직렬화를 하겠다는 설정인데 이는 굉장히 위험한 설정이다.
현재는 redis가 private instance에 떠있고 지금 어플리케이션에서만 사용하기 때문에 안전한 객체만이 들어오기 때문에 당장은 문제가 없다.
하지만 &lt;strong&gt;&lt;em&gt;redis를 통해 위험한 객체가 들어오면 무방비인 상태이기 때문에 화이트리스트 설정 및 DefaultTyping을 더 안전한 옵션으로 바꿔줘야한다.&lt;/em&gt;&lt;/strong&gt;
내가 일단 이렇게 한 이유는 화이트리스트 객체를 설정하는 효율적인 기준에 대한 학습이 부족하고, 무엇이 안전한지 최선의 방법을 모르기 때문이다. 몇몇 방법을 적용해봤는데, 적용하기 굉장히 까다로워서 코드가 많이 수정되거나, API 스펙이 바뀌는 경우가 발생했다. 깊게 학습한 후에 최선의 방법을 찾아서 변경할 예정이다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3af609e940e979e2a723b0fb620aadf1/171ca/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 12.941176470588234%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAkUlEQVR42k2OyxLDIAhF8y0xFlR8pDPtIo19/f8/3SLpIoszXFCGM0lZIbkZSeGQkcesXpGkIqaCC0UQJ+2b9TFVhFiUbHnMxl8OjOl239CfH/T+0vrF3t/YHxuorfAU4BbGvJBWwuLZcIN/705vs/OYOIjarXa9qJXkajCLGQS9Pqwtx2I2Y+ewOzJHseyJ8QMDR1qfWQ0jGwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/3af609e940e979e2a723b0fb620aadf1/ca1dc/3.png&apos; srcset=&apos;/static/3af609e940e979e2a723b0fb620aadf1/e7570/3.png 170w,
/static/3af609e940e979e2a723b0fb620aadf1/f46e7/3.png 340w,
/static/3af609e940e979e2a723b0fb620aadf1/ca1dc/3.png 680w,
/static/3af609e940e979e2a723b0fb620aadf1/02d09/3.png 1020w,
/static/3af609e940e979e2a723b0fb620aadf1/9d567/3.png 1360w,
/static/3af609e940e979e2a723b0fb620aadf1/171ca/3.png 1684w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이 부분은 redisCache 설정 관련된 부분이다. ttl을 30분으로 설정하고 Null인 데이터는 캐싱하지 않겠다는 뜻이다. 그리고 위에서 정의한 serializer를 등록해준다.&lt;/p&gt;
&lt;p&gt;그리고 Config 파일에 &lt;code class=&quot;language-text&quot;&gt;@EnableCaching&lt;/code&gt;을 붙혀주면 redis를 이용해 캐싱을 사용할 준비를 마치게된다.&lt;/p&gt;
&lt;h3&gt;[Spring AOP를 통해 Cache 적용하기]&lt;/h3&gt;
&lt;p&gt;Spring은 Cache를 AOP를 통해서 프로덕션 코드에 비침투적이고 쉽게 적용할 수 있다. 방법은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2bddf32b507e9524818c1c574848fd01/91425/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 5.88235294117647%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAYAAADeko4lAAAACXBIWXMAABYlAAAWJQFJUiTwAAAARUlEQVR42h3JyRGAIBAAQWOB5UZdECT/yEaLR7/6GJrp7eRdi1s7Xh9qm8ze0TZINSM5IClggsc6T6nXZsRho98nJf4nfL/dHgt8cR81AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;4&apos; title=&apos;&apos; src=&apos;/static/2bddf32b507e9524818c1c574848fd01/ca1dc/4.png&apos; srcset=&apos;/static/2bddf32b507e9524818c1c574848fd01/e7570/4.png 170w,
/static/2bddf32b507e9524818c1c574848fd01/f46e7/4.png 340w,
/static/2bddf32b507e9524818c1c574848fd01/ca1dc/4.png 680w,
/static/2bddf32b507e9524818c1c574848fd01/02d09/4.png 1020w,
/static/2bddf32b507e9524818c1c574848fd01/9d567/4.png 1360w,
/static/2bddf32b507e9524818c1c574848fd01/91425/4.png 1556w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;@Cacheable&lt;/code&gt; 어노테이션을 이용하면 해당 메소드에 쉽게 캐시를 적용할 수 있다. 동작 과정은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;해당 메서드(findRoadmap)이 실행되기 전에 CacheHit를 한다.&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&gt;그리고 몇몇 옵션을 설정할 수 있는데 하나씩 살펴보자.&lt;/p&gt;
&lt;h4&gt;Value&lt;/h4&gt;
&lt;p&gt;CacheName을 설정하는 옵션이다. 이는 cache의 식별자로 사용이되며 생명주기가 같은 캐시끼리 같은 이름을 맞추어야한다.&lt;/p&gt;
&lt;h4&gt;KeyGenerator&lt;/h4&gt;
&lt;p&gt;캐시에 적용되는 키 값을 생성하는 객체를 설정할 수 있다. key를 설정하는 제일 간단한 방법은 SpEL을 이용하는 것이다. 좀 더 정교하게 키를 생성하고 싶은 경우 해당 옵션을 사용하여 Key를 생성하는 객체를 설정할 수 있다.&lt;/p&gt;
&lt;h4&gt;CacheManager&lt;/h4&gt;
&lt;p&gt;메소드마다 사용할 CacheManager를 설정하는 방법이다. 메소드마다 적용하고 싶은 옵션이 다를 수도 있으니 해당 옵션을 통해 직접 CacheManager를 설정하여 메소드에 맞는 설정을 적용할 수 있다.&lt;/p&gt;
&lt;p&gt;이외에도 여러가지 옵션이 있으니 필요에 따라 활용하면 된다.&lt;/p&gt;
&lt;h3&gt;[Spring AOP를 통해 캐시 데이터 정합성 맞추기]&lt;/h3&gt;
&lt;p&gt;캐시 적용과 마찬가지로 Spring은 AOP를 활용해서 데이터 정합성을 맞출 수 있도록 추상화 되어있다. 방법은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/43937ec8c2202b8ef721ffa5f3cb6c7c/598cb/5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 7.0588235294117645%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAYAAADeko4lAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAR0lEQVR42h3DCwqAIBBAwU5iJFSg7qqrZXT/e70+AzP1ErFvK0gdBO1ICuRWUWv04+IcN5qN8tYYKSEhUhG1/7rtuMXjZs8D1dgesWt0mVsAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;5&apos; title=&apos;&apos; src=&apos;/static/43937ec8c2202b8ef721ffa5f3cb6c7c/ca1dc/5.png&apos; srcset=&apos;/static/43937ec8c2202b8ef721ffa5f3cb6c7c/e7570/5.png 170w,
/static/43937ec8c2202b8ef721ffa5f3cb6c7c/f46e7/5.png 340w,
/static/43937ec8c2202b8ef721ffa5f3cb6c7c/ca1dc/5.png 680w,
/static/43937ec8c2202b8ef721ffa5f3cb6c7c/02d09/5.png 1020w,
/static/43937ec8c2202b8ef721ffa5f3cb6c7c/598cb/5.png 1230w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;@CacheEvict&lt;/code&gt;를 통해서 해당 메소드가 실행이 되면, value(cacheName)에 맞는 캐시들이 모두 초기화 되게 하는 옵션이다. 나 같은 경우에는 캐시에 정렬과 페이징이 적용이 되어있어서 어떤 피드 추가, 삭제, 수정이 되면 모든 캐시를 초기화 하도록 해서 데이터 정합성을 맞추었다. 만약 특정 캐시만 삭제하고 싶거나 복잡한 비즈니스 로직이 있으면 해당 어노테이션의 옵션을 사용하던가 직접 AOP를 구현하는 방법을 사용할 수 있다.&lt;/p&gt;
&lt;h2&gt;[성능 측정]&lt;/h2&gt;
&lt;p&gt;어플리케이션에 Redis를 적용했으니 얼마나 성능이 개선 되었는지 테스트 해보자. 다음과 같은 환경으로 테스트를 진행했다.&lt;/p&gt;
&lt;p&gt;테스트 도구 : postman&lt;/p&gt;
&lt;p&gt;테스트 환경 : local&lt;/p&gt;
&lt;p&gt;테스트 API : 메인 페이지에 나가는 피드 조회 API를 선택&lt;/p&gt;
&lt;p&gt;조건 : 정렬 조건은 최신순, size는 20으로 설정&lt;/p&gt;
&lt;h3&gt;[Redis Cache 적용 전]&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 568px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0f157e9c045eb1943b8ead4b17b15991/d63a8/6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 10%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAa0lEQVR42iVOQRLEIAzqX2o1IVHXzjj+/2VUswcOBAhcay3WWiki7L1TVYlhG068zvSk0AFQKmhv5V1ScHenNFC70WdjRuE15wyhlMIxBs0sDPj9cac7bsdzAraLkmRCwdZalOh+egY8mvkB6ho8KYFAszoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;6&apos; title=&apos;&apos; src=&apos;/static/0f157e9c045eb1943b8ead4b17b15991/d63a8/6.png&apos; srcset=&apos;/static/0f157e9c045eb1943b8ead4b17b15991/e7570/6.png 170w,
/static/0f157e9c045eb1943b8ead4b17b15991/f46e7/6.png 340w,
/static/0f157e9c045eb1943b8ead4b17b15991/d63a8/6.png 568w&apos; sizes=&apos;(max-width: 568px) 100vw, 568px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;[Redis Cache 적용 후]&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 566px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/07fc3be66357d6891c04cc180d8327e6/7ef45/7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 13.529411764705882%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAj0lEQVR42jWNQQ7DIAwE8xTANgjSoCakBeVQ8f9PbcFKDqO1hrVZRATOOVhrYYzRJCK4yfBznsw37RmrPG72p39Yeu+YR1trqLUipYSjf5Hbjv33AQujlIKznHgdm7qQI9a0otWGbc/I14H3VVDG3hJj1F+89wgDZgZ7AWkyrLPqvPjhCBJEkxwhhHD3HwR/SvlYAHMCiloAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;7&apos; title=&apos;&apos; src=&apos;/static/07fc3be66357d6891c04cc180d8327e6/7ef45/7.png&apos; srcset=&apos;/static/07fc3be66357d6891c04cc180d8327e6/e7570/7.png 170w,
/static/07fc3be66357d6891c04cc180d8327e6/f46e7/7.png 340w,
/static/07fc3be66357d6891c04cc180d8327e6/7ef45/7.png 566w&apos; sizes=&apos;(max-width: 566px) 100vw, 566px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;[정리]&lt;/h2&gt;
&lt;p&gt;성능 개선 : 70ms -&gt; 9ms&lt;/p&gt;
&lt;p&gt;성능 개선 퍼센트 : 87% 개선&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[Redis] Redis Cache를 활용한 성능 개선기 (1)]]></title><description><![CDATA[들어가며 프로젝트에 캐싱을 통해서 성능 개선을 하면서 Redis를 사용한 경험을 기록하고자 이 글을 쓰게 되었다. 캐싱에 레디스를 선택한 이유 높은 성능 : Redis…]]></description><link>https://hoonblog.netlify.app/performance-improvement-with-redis-cache-1/</link><guid isPermaLink="false">https://hoonblog.netlify.app/performance-improvement-with-redis-cache-1/</guid><pubDate>Fri, 15 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;프로젝트에 캐싱을 통해서 성능 개선을 하면서 Redis를 사용한 경험을 기록하고자 이 글을 쓰게 되었다.&lt;/p&gt;
&lt;h2&gt;[캐싱에 레디스를 선택한 이유]&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;높은 성능 : Redis는 기본적으로 전체 데이터를 메모리에서 관리한다. 데이터 백업 같은 작업은 디스크에 저장하긴 하지만 이는 비동기로 작동하기 때문에 응답 성능에는 거의 영향을 미치지 않는다. 그에 반해 RDB는 기본적으로 데이터를 디스크에서 관리한다. 요즘 RDB들도 메모리를 많이 활용하긴 하지만 결국에는 디스크에 저장된다. 즉, Redis는 RDB와 다르게 Disk I/O가 자주 발생하지 않기 때문에 성능이 몇 배 빠를 수 밖에 없다.&lt;/li&gt;
&lt;li&gt;개발 용이성 : 어플리케이션과 연동하기 쉽게 여러 개발 언어를 지원한다. 그리고 다른 NoSQL과는 다르게 문법이 직관적이고, 개발 코드 양 또한 적다. 또한 싱글스레도로 명령을 처리하기 때문에 개발자가 race condition에 대한 걱정을 거의 안해도 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;여기까지는 Memcached와 같은 메모리 기반 캐시와 비슷하다. 하지만 Redis는 다음과 같은 차이점을 가지고있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;다양한 자료 구조: Redis는 자체적인 Collection을 가지고 있다. 단순 String뿐만 아니라 List, Set, Sorted Set, Hash 등 여러가지 자료구조를 가지고 있다. 이를 응용해서 여러가지 요구사항을 효율적으로 처리할 수 있는 장점이 있다. &lt;/li&gt;
&lt;li&gt;고가용성(High Availability) : Redis는 단순 Replication 뿐만 아니라, 고가용성을 위해 Sentinel과 Cluster를 지원한다. 이는 하나의 Redis 인스턴스에 오류가 생겨도 개발자의 다른 설정 없이 자동으로 다른 인스턴스로 대체할 수 있도록 해준다. 이를 페일 오버 기능이라고 하고 이 기능을 통해 고가용성을 확보할 수 있게 해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;반면에 Redis는 메모리 기반으로 동작하기 때문에 캐싱 데이터의 크기가 할당된 메모리 용량보다 큰 경우에 사용할 수 없다. 그리고 Memcached는 멀티 쓰레드로 작동하기 때문에 Redis보다 성능이 좀 더 좋다고 할 수 있다.&lt;/p&gt;
&lt;p&gt;이번 프로젝트에서는 redis로 감당하지 못할 만큼 용량이 엄청나게 큰 데이터를 캐싱할 일이 없다. 그리고 위에 나온 장점을 모두 활용하고, redis를 데이터 저장소처럼 사용하는 경우도 있기 때문에 redis를 도입하기로 결정했다.&lt;/p&gt;
&lt;h2&gt;[캐싱 전략 선택]&lt;/h2&gt;
&lt;h3&gt;읽기 전략&lt;/h3&gt;
&lt;p&gt;캐싱 읽기 전략에는 크게 Cache Aside와 Read Through이 있다. 이 둘을 비교해보자.&lt;/p&gt;
&lt;h4&gt;Cache Aside&lt;/h4&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/026acbb6fa2dc8b32c9d240c003c4c7e/663f3/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABFklEQVR42p2S626DMAyF+/7PuB+bKpZxJyRxbiRnJh0XVd1aLWAFAjr+fOwL/lh5jZxL4Of52br8+iXxvWQostActwQJgQAtPbphxDDKEkrpPdlDwcVldCJAzBLXukXV9Dsh+YhBagg+r9u+hNIG+RFhDoAYZ3zOE3S0WJhoUgazod2DLkjUboQjD2MtnPcg3lNKN8FNeZw1ml6hsgNkNHc+Hi9qIXTEokzddgOXPpXd+XAQxiWVst4qAUmGuditUyM2f1LKhVpZwvtHhSv/v/kYQjwEV3XBWYx1XKpD7ScIN8BGX5qijC2U6dUurwSKfSLnjzL5ouDx1U9omKAQ5nRYkZ+Mzbm08zo3ZTP+f3N4N9yvDvY3i2sSF+NKBiMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/026acbb6fa2dc8b32c9d240c003c4c7e/663f3/1.png&apos; srcset=&apos;/static/026acbb6fa2dc8b32c9d240c003c4c7e/e7570/1.png 170w,
/static/026acbb6fa2dc8b32c9d240c003c4c7e/f46e7/1.png 340w,
/static/026acbb6fa2dc8b32c9d240c003c4c7e/663f3/1.png 650w&apos; sizes=&apos;(max-width: 650px) 100vw, 650px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Cache Aside 패턴을 위 그림 순서대로 설명하면 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(1) 캐시에 해당 데이터가 있는지 확인한다(Cache hit). 만약 데이터가 있으면 바로 데이터를 반환한다.&lt;/li&gt;
&lt;li&gt;(2) 캐시에 데이터가 없으면(Cache miss) DB에 쿼리를 날려서 데이터를 찾아온다.&lt;/li&gt;
&lt;li&gt;(2.2) 데이터를 캐시에 적재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 패턴의 장점은 캐시에 문제가 생겨도 Application에는 문제가 없다는 것이다. 캐시에 장애가 발생하여서 Cache miss가 발생하여도 그냥 DB로 가서 데이터를 가져오면 된다. 즉, Application의 안정성이 높다.&lt;/p&gt;
&lt;p&gt;다만, 캐시가 죽은 경우 순간적으로 DB에 Connection이 쏠려 순간적으로 부하가 걸릴 수 있다는 단점이 있다.&lt;/p&gt;
&lt;h4&gt;Read Through&lt;/h4&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b7c347c04099f8be0c201dc51ac613b9/663f3/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABD0lEQVR42q2S2W7DIBBF8/8f18f2pa2iNspig2z2dbgFx0ncuHmoFKQRy8AZ7oUNntw2v2YFoLyOfwOJCqS1SB6QpzruCtQcXp/zKT8mtxyVcgNq6/H6+YWeKzhNcPYcxiT4kMFHhSMfoL2vIsp0mApNABMCBqkxKnMDtoWeCwxO49swMCfROwERLVyO4ELh0A3Yqg7HMKALAqfat7EMFkc2TowrsF2WMsHmgJ1j2FuGg+VIs4GZCKXKZlHi3ezxIj7wpnfgdV5myWUpGdfFvz2iCrx46ChUkEKaJU8F74Ex5eqBrn26PDaW7BATjPOrQtO+ChLGVq/jQnIzucl68IqtOC2uf7+v5VaSn/WxfwAPixPKikycjwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/b7c347c04099f8be0c201dc51ac613b9/663f3/2.png&apos; srcset=&apos;/static/b7c347c04099f8be0c201dc51ac613b9/e7570/2.png 170w,
/static/b7c347c04099f8be0c201dc51ac613b9/f46e7/2.png 340w,
/static/b7c347c04099f8be0c201dc51ac613b9/663f3/2.png 650w&apos; sizes=&apos;(max-width: 650px) 100vw, 650px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Read Through 패턴을 위 그림 순서대로 설명하면 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(1) 캐시에 해당 데이터가 있는지 확인한다(Cache hit). 만약 데이터가 있으면 바로 데이터를 반환한다.&lt;/li&gt;
&lt;li&gt;(3.1) 캐시에 데이터가 없으면 캐시에서 데이터베이스에 접근하여 데이터를 가져온다.&lt;/li&gt;
&lt;li&gt;(3.2) 데이터를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 패턴은 사실 Redis로 구현하기 조금 힘들다. Redis에서 직접 DB에 접근하는 기능이 없는 것 같다. DynamoDB와 DAX를 이용해서 구현이 가능하다고는 한다.
cache aside 전략과 차이점은 DB에 접근하는 주체에 있다. Cache에서 DB에 접근하게 되면 Application은 단순하게 Cache와의 Connection만을 유지하면 되므로 부담이 적다.&lt;/p&gt;
&lt;p&gt;하지만 Cache가 장애가 생기면 Application 전체에 장애가 발생하는 위험이 있다. 그리고 cache aside 전략과 마찬가지로 데이터 정합성 문제가 발생할 여지가 있다.&lt;/p&gt;
&lt;h4&gt;Cache Aside를 선택한 이유&lt;/h4&gt;
&lt;p&gt;두 전략 모두 데이터 정합성에 대한 이슈가 있다. 하지만 이는 데이터 변경/삽입/삭제 시 고려해야하는 문제이므로 선택 기준에서 제외했다.
Cache Aside를 사용하게 되면 Application의 안정성을 확보할 수 있다. 그리고 Read Through는 redis로 구현하기가 힘들기도하고, 안정성이 떨어진다. 그래서 &lt;code class=&quot;language-text&quot;&gt;Cache Aside&lt;/code&gt; 전략을 사용하도록 결정했다.&lt;/p&gt;
&lt;h3&gt;쓰기 전략&lt;/h3&gt;
&lt;h4&gt;Write-through&lt;/h4&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/99412d728f48eaadef8c33f3f6c2f0cb/663f3/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA0UlEQVR42rWS2w6CMBBE+f9P9Mn4IFB7ocDSi4FxuyaiRoyJ2mbTZKc9nUxb4cejem4sy/JQn2qbwJ84lBt5JSI0TYO2bdF1Hbz3iDHeNpde0ZVSskdrLf15Xh0LMOUzdocjnO8F4pxDCEFgOSX0NKEbiLUexhgBaW1grQVNEygmUIgr0PoB+6Pig4Scs4AKUIoP1CeDQ60xMrjoiS8plXOCdexaOyjrVyCFBDeMbH1+mUtMmR2Om7kVQ/043WXIs8C2Xu6aM95qDxn+9R9+C7wApj4UhUToP70AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/99412d728f48eaadef8c33f3f6c2f0cb/663f3/3.png&apos; srcset=&apos;/static/99412d728f48eaadef8c33f3f6c2f0cb/e7570/3.png 170w,
/static/99412d728f48eaadef8c33f3f6c2f0cb/f46e7/3.png 340w,
/static/99412d728f48eaadef8c33f3f6c2f0cb/663f3/3.png 650w&apos; sizes=&apos;(max-width: 650px) 100vw, 650px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Write-throught 패턴을 위 그림 순서대로 설명하면 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(1) Application에서 쓰기 요청 시 Cache에 데이터를 넣는다.&lt;/li&gt;
&lt;li&gt;(2)그 데이터를 그대로 DB에 넣는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Write Back(Behind) 패턴&lt;/h4&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f002e08013a384ad9d3b6a279d455257/663f3/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA2UlEQVR42s1SXW/CMAzk///EPQ3RFhqV1PkO6dojtkRgTNsTSHN0SmQ7l/MpO7w4dm8lLKXAOQdrbduXZWn1nLPkvfeCGCO2bftJyElOhxDQ9z26rsMwDIKUUrtERC0/jiOUUvIIl289QngpCz72PYwPosoY03CeJkyaQD5KH19c11XA55QvCCkLGqE2Dp9HBarjMMlclbAa4vOscRhGHE5nWOdFMY/KSClCz4TTRFDa3AmZnVxAqX7x2N9R/QpR1P8WLMjWnruHdX3xGE8GP8b2Z+3Jw3/9D6/5dhIQQXKuRgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;4&apos; title=&apos;&apos; src=&apos;/static/f002e08013a384ad9d3b6a279d455257/663f3/4.png&apos; srcset=&apos;/static/f002e08013a384ad9d3b6a279d455257/e7570/4.png 170w,
/static/f002e08013a384ad9d3b6a279d455257/f46e7/4.png 340w,
/static/f002e08013a384ad9d3b6a279d455257/663f3/4.png 650w&apos; sizes=&apos;(max-width: 650px) 100vw, 650px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Write Back 패턴은 Write Through와 비슷하지만, cache에서 db로 배치 업데이트를 하는 식이다.
이 패턴도 Cache와 DB와의 정합성을 맞추는데 용이하다는 장점이 있다.
하지만 Cache에 있는 데이터가 아직 DB에 반영되지 않고, Cache가 죽을 경우 데이터가 유실될 위험이 있다.&lt;/p&gt;
&lt;p&gt;이 전략 또한 캐싱 하는 데이터가 여러 테이블을 join하는 복잡한 구조의 json 데이터여서 사용하기에 불편했다.&lt;/p&gt;
&lt;p&gt;이 패턴은 DB와 캐시가 항상 동기화 되어있어 Cache의 데이터를 최신의 상태로 유지가 가능하다. 데이터 유실이 발생하면 안되는 상황에 유리한 조건이다.
하지만 나의 경우 캐싱 하는 데이터가 여러 테이블을 join하는 복잡한 구조의 json 데이터여서 사용하기에 불편했다.&lt;/p&gt;
&lt;h4&gt;Write Around 패턴&lt;/h4&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/60c2c59057bb4091b61c9bfb82516082/663f3/5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABO0lEQVR42p1SAXKDIBDM/x/ZjkmMGkFAAQGB7UHGJp2mk7Y4Nzrn3d7ucgf84eScX9Ycfu6miECKCc4HRHpnerwBZuHB+EQhIOSMlNJrwGXM4MJhmCXagUPMugLGAAhhcGw7TEJV0BC274CRphRFgRg0gqM3Emv2WL3HwOnb+Vo3bBK9E7B6hV0djF1r7HYcdrCmu0ItFvPq0QVqSO7TNxcCUr7JUmYBV7IyKwwXbTAvGtu23QElJU4DoxhhnSWf3M3DJ7YarSGVwpVN1T9Pw1ZiGmO8AyptwehnSBGd5ni/nNBLRtM1+RMqw600ECKLC47qiqa54HwZcG57dP2I8MiwFBuasie3HPFmerR6RM9YvZCiosj3KWAhFZwke/K33PCvbnk/ZUhH8vSD8f/bw4dlts7VPfyafw74AaYED3smo7tAAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;5&apos; title=&apos;&apos; src=&apos;/static/60c2c59057bb4091b61c9bfb82516082/663f3/5.png&apos; srcset=&apos;/static/60c2c59057bb4091b61c9bfb82516082/e7570/5.png 170w,
/static/60c2c59057bb4091b61c9bfb82516082/f46e7/5.png 340w,
/static/60c2c59057bb4091b61c9bfb82516082/663f3/5.png 650w&apos; sizes=&apos;(max-width: 650px) 100vw, 650px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Write Around 패턴을 위 그림 순서대로 설명하면 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(1)DB에 데이터를 쓴다.&lt;/li&gt;
&lt;li&gt;(2)데이터 조회 시 데이터가 캐시에 있으면 데이터를 반환한다.&lt;/li&gt;
&lt;li&gt;(3.1) 데이터가 없을 시 DB에서 데이터를 가져온다.&lt;/li&gt;
&lt;li&gt;(3.2) 데이터를 캐시에 적재하고 응답값을 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 패턴의 경우 사실 쓰기 전략이라고 하기 애매하긴 하다. Cache Aside 패턴과 DB에 쓰는 방법을 합친 패턴이라고 볼 수 있다.
가장 직관적이고 효율적인 방법이지만 캐시와 DB와의 데이터 정합성이 맞지 않을 수도 있다는 단점이 있다.&lt;/p&gt;
&lt;h4&gt;Cache Aside를 선택한 이유&lt;/h4&gt;
&lt;p&gt;Write Through와 Write Back 패턴은 위에서도 얘기 했듯이 복잡한 데이터를 캐싱하기에 구현이 힘들다. DB 상에서 여러 테이블을 join 하고 어플리케이션에서 가공한 데이터를 캐싱하는데, 단순히 데이터를 넣거나 업데이트 할때 이러한 복잡한 데이터를 변경하기 힘들다.
물론 Event나 AOP를 활용하여 구현할 수 있겠지만, 캐싱에서 변경되는 데이터 대상이 하나가 아니기 때문에 비효율적이라고 느꼈다. 그리고 캐싱이 적용되는 데이터들은 변경이 많지 않은 데이터였기 때문에 굳이 이 전략들을 사용할 필요가 없었다.
Write Around는 쓰기 작업 시 단순히 DB에 데이터를 넣기만 하면된다. 동시에 데이터 정합성을 맞추기 위해서 캐싱 되어있는 데이터들을 Redis에서 삭제했다. 이렇게 되면 해당 데이터 조회 시 캐시에 없으므로 DB에서 값을 가져와서 캐시에 적재하고, 그 다음부터는 캐시된 데이터를 사용하게 된다. 내가 선택한 프로세스는 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;쓰기 요청 시 DB에 데이터를 넣음&lt;/li&gt;
&lt;li&gt;동시에 Redis에 있는 기존 데이터들 삭제&lt;/li&gt;
&lt;li&gt;읽기 요청 시 Redis 확인. 존재하면 바로 반환&lt;/li&gt;
&lt;li&gt;존재하지 않으면 DB에서 가져와서 Redis에 적재&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;캐싱 전략 선택 정리&lt;/h3&gt;
&lt;p&gt;위와 같은 이유로 읽기 전략은 Cache Aside, 쓰기 전략은 Write Around를 사용했다. 캐싱 프로세스는 다음과 같다.&lt;/p&gt;
&lt;p&gt;[읽기]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;데이터가 Redis에 존재하는지 확인한다. 존재하면 바로 반환한다.&lt;/li&gt;
&lt;li&gt;데이터가 존재하지 않으면 DB에 가서 읽어온다.&lt;/li&gt;
&lt;li&gt;읽어온 데이터를 Redis에 적재하고 반환한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;[쓰기]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;데이터를 DB에 저장한다.&lt;/li&gt;
&lt;li&gt;Redis에 존재하는 해당 데이터와 관련된 캐시들을 모두 삭제한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;생각보다 글이 너무 길어져서 1, 2편을 나눴습니다. Spring boot에서 Redis Cache 적용하기를 보려면 다음 글을 참고해주세요!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[Spring] Event로 느슨한 결합 사용하기]]></title><description><![CDATA[들어가며 이번 프로젝트를 진행하며 Event…]]></description><link>https://hoonblog.netlify.app/loose-combination-with-event/</link><guid isPermaLink="false">https://hoonblog.netlify.app/loose-combination-with-event/</guid><pubDate>Fri, 08 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;이번 프로젝트를 진행하며 Event를 활용하여 요구사항을 해결한 적이 있다. 그 과정을 기록하고자 이 글을 쓰게 되었다.&lt;/p&gt;
&lt;h2&gt;[요구사항]&lt;/h2&gt;
&lt;p&gt;피드를 생성하는 로직이 있다. 이 피드는 각 단계가 있고, 각 단계에 사진 파일이 여러개 저장될 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/430cc180dad2bed1d66f4c3ac44dcee9/28a3f/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 51.17647058823529%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABiklEQVR42oVSu4rCUBBNfKAiGlCEqOCj8pEVk4DPiKCCiIWKlZWlPyAIgj9gbW1j41/4IzYWlmn8guPOsFfjrrKBk7nMi5lzRlIUBb1eD4ZuQPvSYFkWRqMRWq0W0uk0arUaut0uqtUq6vU6hsMhOp0OBoMB11G8WCxiMpkgHA5D+v4gyzLcbjdbJyjmcrnYUpzeBBFzWo/Hw2/p5/cIiCLRSBQJBINBGIaBRqOBUqmEfD6PTCbjzJVeCmOxGEKh0IvP6/UiGo2i3+9zg0qlgna7zfTsdjssl8vHFpKzaLVaYTweY7FYYD6fsz+VSqHZbELXdZ5ENJ5Op8ytqqrsSyQSiEQiz4Y+nw/n8xmXywW32w3H45H9RDpNQwLRmtlsllcmgUiow+GA9XqN/X6PzWbzbEicnU4nXK9X2LaN7XbL/kAggFwuh0KhAE3TeBpSejab8aQkBuUQ/H7/qyjkoJMwTfOPGBQrl8vcnCgQZ/NGOAn/wXkqRHwymWRu4/H4u/zPxb/hvM9PuANRbxJXFcgTKAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/430cc180dad2bed1d66f4c3ac44dcee9/ca1dc/1.png&apos; srcset=&apos;/static/430cc180dad2bed1d66f4c3ac44dcee9/e7570/1.png 170w,
/static/430cc180dad2bed1d66f4c3ac44dcee9/f46e7/1.png 340w,
/static/430cc180dad2bed1d66f4c3ac44dcee9/ca1dc/1.png 680w,
/static/430cc180dad2bed1d66f4c3ac44dcee9/02d09/1.png 1020w,
/static/430cc180dad2bed1d66f4c3ac44dcee9/28a3f/1.png 1100w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이 로직은 간단해보이지만 다음과 같은 문제점이 있다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;I/O가 실패하여 사진이 없어도 피드 생성 자체는 되어야한다라는 요구사항이 있다.&lt;/li&gt;
&lt;li&gt;I/O중 예외가 발생하면 피드 생성 자체가 롤백된다.&lt;/li&gt;
&lt;li&gt;각 사진 파일은 I/O가 발생한다. 한 요청에 파일 I/O가 10번이상 발생할 수 있으니 트랜잭션이 굉장히 길게 걸린다.&lt;/li&gt;
&lt;li&gt;파일 I/O 후 경로와 같은 메타 데이터를 DB에 저장해야한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;즉, 파일 I/O하는 서브 로직은 피드 생성이라는 본 로직과 강하게 결합되면 안된다는 결론이 나온다.&lt;/p&gt;
&lt;h2&gt;[고려한 방법]&lt;/h2&gt;
&lt;p&gt;다음과 같은 방법을 고려했었다.&lt;/p&gt;
&lt;h3&gt;스프링 트랜잭션 전파(Spring Transaction propagation) 레벨 활용&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;Spring&lt;/code&gt;의 &lt;code class=&quot;language-text&quot;&gt;Transaction propagtion&lt;/code&gt;을 활용하여서 피드 생성 트랜잭션과 파일 I/O 트랜잭션을 분리할 수 있다.
&lt;code class=&quot;language-text&quot;&gt;Progation.REQUIRES_NEW&lt;/code&gt;를 이용하면 쉽게 분리할 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;하지만 이 방법은 단순히 트랜잭션만 분리한 방법이다. 즉, 두 로직의 결합도를 낮추지는 못한다.&lt;/p&gt;
&lt;p&gt;이러한 문제의 일환으로 피드 생성 트랜잭션이 파일 I/O 트랜잭션과 강하게 결합되어있기 때문에 여전히 굉장히 오래 걸린다. 즉, 피드 생성 트랜잭션의 시간이 파일 I/O 트랜잭션에 영향을 받는 것이다.&lt;/p&gt;
&lt;h2&gt;[해결책]&lt;/h2&gt;
&lt;p&gt;그래서 생각한 방법은 &lt;code class=&quot;language-text&quot;&gt;Spring Event&lt;/code&gt;를 활용하는 것이었다. 피드를 생성하는 본 로직에서 특정 &lt;code class=&quot;language-text&quot;&gt;Event&lt;/code&gt;를 발행하고, &lt;code class=&quot;language-text&quot;&gt;EventListener&lt;/code&gt;에서 파일 I/O를 하는 방법이다.&lt;/p&gt;
&lt;p&gt;다음은 내가 고민했던 부분이다. 여기서는 비동기 &lt;code class=&quot;language-text&quot;&gt;Event&lt;/code&gt;와 관련된 내용은 설명하지 않는다.&lt;/p&gt;
&lt;h3&gt;두 로직의 결합도 낮추기&lt;/h3&gt;
&lt;p&gt;처음에는 다음과 같이 이미지를 저장하는 이벤트인 &lt;code class=&quot;language-text&quot;&gt;FeedStepImageSaveEvent&lt;/code&gt;를 발생 시켰다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2d23fd9ba92222bb3a4ad6faca6c5af3/d4fa6/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 15.294117647058824%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAjklEQVR42mXOawrCQAwE4N7G1nZf3Uc2u9Fa8P5XGtMKgvrjY0IgQwamO6Q+UOkGmzpS6Si1Y40E6zN8KGeOJuEy/xuXb4OzDRs90eqOTh17Fwg3rEXgkyDGpircWmD823JwGUZd7U/hpMviGTkw6KBzdIw5bpjzrkWbFop+3VBZQJoxM1LSG80lECaTP14yql/Lf0q3UwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/2d23fd9ba92222bb3a4ad6faca6c5af3/ca1dc/2.png&apos; srcset=&apos;/static/2d23fd9ba92222bb3a4ad6faca6c5af3/e7570/2.png 170w,
/static/2d23fd9ba92222bb3a4ad6faca6c5af3/f46e7/2.png 340w,
/static/2d23fd9ba92222bb3a4ad6faca6c5af3/ca1dc/2.png 680w,
/static/2d23fd9ba92222bb3a4ad6faca6c5af3/02d09/2.png 1020w,
/static/2d23fd9ba92222bb3a4ad6faca6c5af3/9d567/2.png 1360w,
/static/2d23fd9ba92222bb3a4ad6faca6c5af3/d4fa6/2.png 1598w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이 로직은 &lt;code class=&quot;language-text&quot;&gt;EventListener&lt;/code&gt;에서 비동기로 쓰레드를 새로 생성해서 이미지 저장 로직을 수행하기 때문에 물리적인 의존도는 줄었다고 볼 수있다.&lt;/p&gt;
&lt;p&gt;하지만 이미지 저장 로직의 정책이 바뀌어서 이벤트가 변경 되었을때, 피드 저장 로직의 이벤트도 함께 변경이 되어야한다. 어떤 일을 해야 하는 지를 메시지 발행자가 알려주는 경우(Command), 해야하는 일이 변경될 때 메시지 발행자와 수신자 양쪽 모두의 코드가 변경돼야 하기 때문에 높은 결합도가 존재하게 된다.&lt;/p&gt;
&lt;p&gt;또한 이미지 저장 로직 자체를 발행하며 이미지 저장이라는 비즈니스 로직을 알고있으니 논리적으로도 결합이 느슨해졌다고 얘기할 수 없다. 즉, 물리적인 의존도는 줄었지만 개념적으로는 의존도가 높은 것이다.&lt;/p&gt;
&lt;p&gt;메시지 발행 시 대상 도메인에게 기대하는 목적을 담았기 때문에 의존도가 남아있다. 대상 도메인에게 기대하는 목적을 담았다면, 이는 이벤트라 부르지 않는다고 한다. 이것은 이벤트 시스템을 활용한 비동기 요청이다.&lt;/p&gt;
&lt;p&gt;이를 다음과 같이 수정했다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c150ee5ba00b98cb6e54a46873c8f1b2/d4fa6/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 15.294117647058824%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAiUlEQVR42mXOWw6CMBBGYVejXAvT0im0NKBx/1s6Vkk0kYeT/+2bucx+Y09PUtyxIaNLJqYVDQtilckptmxtJq6t49ZO36ru3KXtA8nfibqTNfFYVnKIiM8Y3bBTxruI8zPiAkPBxZYVpTH+DFbl8th7xGjZo6HUSKK2K90YMcOBfUD5ge+v/8EXUn9fTHHVusUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/c150ee5ba00b98cb6e54a46873c8f1b2/ca1dc/3.png&apos; srcset=&apos;/static/c150ee5ba00b98cb6e54a46873c8f1b2/e7570/3.png 170w,
/static/c150ee5ba00b98cb6e54a46873c8f1b2/f46e7/3.png 340w,
/static/c150ee5ba00b98cb6e54a46873c8f1b2/ca1dc/3.png 680w,
/static/c150ee5ba00b98cb6e54a46873c8f1b2/02d09/3.png 1020w,
/static/c150ee5ba00b98cb6e54a46873c8f1b2/9d567/3.png 1360w,
/static/c150ee5ba00b98cb6e54a46873c8f1b2/d4fa6/3.png 1598w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;대상 도메인에게 기대하는 목적을 담는게 아닌 피드 생성 이벤트 자체를 발생시킨다.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;FeedCreateEvent&lt;/code&gt;를 listen하는 객체에서 이미지를 저장한다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/af7bd7fe2b40b2cbe1ca8fc365e70128/e7c3c/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 19.411764705882355%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAYAAACOXx+WAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAoElEQVR42nWQyw6CMBBF+RvAtpbSx9AWTDHERIz//znXUeLCpC5OzmruzNwmpoTRZriQYX2CNgEn5dBKi1a4v3SyTrNvV+zbilIKHGVQukDbhF4QhA5Qw4HU/of30mqgdxuI7hiWJ1R+wOQbh66Y3RVLmkExgqbI109wjuDZgX02Hl0ltOlNhvAr5IcCYyeMI3ENhIHdKc/v87A8/KVXdV4C1X7O/4SxdAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;4&apos; title=&apos;&apos; src=&apos;/static/af7bd7fe2b40b2cbe1ca8fc365e70128/ca1dc/4.png&apos; srcset=&apos;/static/af7bd7fe2b40b2cbe1ca8fc365e70128/e7570/4.png 170w,
/static/af7bd7fe2b40b2cbe1ca8fc365e70128/f46e7/4.png 340w,
/static/af7bd7fe2b40b2cbe1ca8fc365e70128/ca1dc/4.png 680w,
/static/af7bd7fe2b40b2cbe1ca8fc365e70128/02d09/4.png 1020w,
/static/af7bd7fe2b40b2cbe1ca8fc365e70128/9d567/4.png 1360w,
/static/af7bd7fe2b40b2cbe1ca8fc365e70128/e7c3c/4.png 1448w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이렇게 하면 피드 생성이라는 본 로직과 파일 저장이라는 서브 로직의 결합도를 물리적, 논리적, 개념적으로 느슨하게 할 수 있다.
피드 생성 로직은 더 이상 파일 저장 로직에 영향을 받지 않는다.&lt;/p&gt;
&lt;h2&gt;[정리]&lt;/h2&gt;
&lt;p&gt;비즈니스 로직에서 분리되어야하는 부분이 있을 때 비동기 Event를 고민할 수 있다. 위 내용에서 &lt;code class=&quot;language-text&quot;&gt;EventListener&lt;/code&gt; 부분에서 Message Queue를 활용하면 시스템 자체를 분리할 수 있다. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[[Spring] 커스텀한 multipart/form-data 요청 받기]]></title><description><![CDATA[들어가며 프로젝트를 진행하며 쉽지 않은 요구사항을 기술적으로 해결한 사례에 대해서 기록하고자 이 글을 쓰게 되었다. 요구사항 피드를 생성하는 API…]]></description><link>https://hoonblog.netlify.app/customized-multi-part-form-receive-data-request/</link><guid isPermaLink="false">https://hoonblog.netlify.app/customized-multi-part-form-receive-data-request/</guid><pubDate>Thu, 07 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;프로젝트를 진행하며 쉽지 않은 요구사항을 기술적으로 해결한 사례에 대해서 기록하고자 이 글을 쓰게 되었다.&lt;/p&gt;
&lt;h2&gt;[요구사항]&lt;/h2&gt;
&lt;p&gt;피드를 생성하는 API를 만들어야하는데 다음과 같은 특이한 요구사항이 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a76dd4dcf6ec0dd5fbb786b35674c47c/28a3f/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 51.17647058823529%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABiklEQVR42oVSu4rCUBBNfKAiGlCEqOCj8pEVk4DPiKCCiIWKlZWlPyAIgj9gbW1j41/4IzYWlmn8guPOsFfjrrKBk7nMi5lzRlIUBb1eD4ZuQPvSYFkWRqMRWq0W0uk0arUaut0uqtUq6vU6hsMhOp0OBoMB11G8WCxiMpkgHA5D+v4gyzLcbjdbJyjmcrnYUpzeBBFzWo/Hw2/p5/cIiCLRSBQJBINBGIaBRqOBUqmEfD6PTCbjzJVeCmOxGEKh0IvP6/UiGo2i3+9zg0qlgna7zfTsdjssl8vHFpKzaLVaYTweY7FYYD6fsz+VSqHZbELXdZ5ENJ5Op8ytqqrsSyQSiEQiz4Y+nw/n8xmXywW32w3H45H9RDpNQwLRmtlsllcmgUiow+GA9XqN/X6PzWbzbEicnU4nXK9X2LaN7XbL/kAggFwuh0KhAE3TeBpSejab8aQkBuUQ/H7/qyjkoJMwTfOPGBQrl8vcnCgQZ/NGOAn/wXkqRHwymWRu4/H4u/zPxb/hvM9PuANRbxJXFcgTKAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/a76dd4dcf6ec0dd5fbb786b35674c47c/ca1dc/1.png&apos; srcset=&apos;/static/a76dd4dcf6ec0dd5fbb786b35674c47c/e7570/1.png 170w,
/static/a76dd4dcf6ec0dd5fbb786b35674c47c/f46e7/1.png 340w,
/static/a76dd4dcf6ec0dd5fbb786b35674c47c/ca1dc/1.png 680w,
/static/a76dd4dcf6ec0dd5fbb786b35674c47c/02d09/1.png 1020w,
/static/a76dd4dcf6ec0dd5fbb786b35674c47c/28a3f/1.png 1100w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;요구사항을 정리하면 다음과 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;피드는 여러개의 단계를 가질 수 있다. 단계의 수는 가변적이다.&lt;/li&gt;
&lt;li&gt;각 단계는 0~2개의 사진 파일을 가질 수 있다. 즉, 사진의 수도 가변적이다.&lt;/li&gt;
&lt;li&gt;피드 생성에 필요한 다른 데이터는 json 형식으로 넘어온다.&lt;/li&gt;
&lt;li&gt;위 요구사항을 하나의 API로 해결해야한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2&gt;[고려한 방법들]&lt;/h2&gt;
&lt;p&gt;다음과 같은 방법들을 고려했었다.&lt;/p&gt;
&lt;h3&gt;API 분리&lt;/h3&gt;
&lt;p&gt;처음에는 이 정도로 큰 요청은 분리를 하는게 맞다고 생각했다. 애초에 API 설계가 잘못되었다는 생각이 들었고, 한번에 해결하기에는 너무 무거운 API라고 생각이 들었다. 그래서 다음과 같은 API 설계로 변경하려고 했다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;피드 생성에 필요한 다른 데이터를 통해 피드를 일단 생성하는 API. 이 요청에서는 사진 파일을 제외한 모든 피드를 생성한다.&lt;/li&gt;
&lt;li&gt;생성된 피드의 각각의 단계에 0~2개의 사진 데이터를 받는 API. 이 요청은 각 단계마다 각각 받거나, 한번에 모두 받는 것 둘 다 고려했다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;이런 API는 다음과 같은 문제점을 가지고 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;h4&gt;완성되지 않은 피드를 생성한다.&lt;/h4&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;2번 API를 각 단계마다 각각 사진 데이터를 받는 형식으로 사용하면, 하나의 피드를 생성하는데 여러번의 API 호출을 해야한다는 문제점이 있다. 만약 그 사이에 해당 피드에 접근하게 되면 완성되지 않은 피드를 사용자가 보게된다. 한번에 모두 받는 방식도 여전히 이러한 문제점이 발생할 여지가 있다.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;h4&gt;어차피 무거운 요청인 것은 변하지 않는다.&lt;/h4&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;2번 API를 각각의 단계에 해당하는 모든 사진을 한번에 받도록하면 원래 API랑 다를게 없다. 원래 API는 2번 API에 단순히 피드 생성에 필요한 json data만 더 받는 것이다. API의 크기의 차이가 아주 미미하다.&lt;/p&gt;
&lt;p&gt;기존의 문제점을 해결하지 못하면서 오히려 다른 기술로 해결할 수 있는 여지를 없애는 방법이다.&lt;/p&gt;
&lt;h3&gt;&lt;code class=&quot;language-text&quot;&gt;@RequestPart&lt;/code&gt; 활용&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;@RequesetPart&lt;/code&gt;를 활용할 생각을 해봤지만 애초에 불가능하다. &lt;code class=&quot;language-text&quot;&gt;@RequestPart&lt;/code&gt;는 &lt;code class=&quot;language-text&quot;&gt;name&lt;/code&gt;으로 구분지어서 json data, 각 단계의 사진들을 받는다. 하지만 각 단계들이 가변적이다. 그래서 애초에 요청을 만들 수가 없다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1ce6b542d9bfcd892553b9d732fab0d6/c371b/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 40.588235294117645%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAABDUlEQVR42qWR3XaDIBCE8zKNBkEBUREQkiY9ff8nmo4/F7lo0otefGf3yDDsjqdpXLCkBVPM0C6gNSOE9riYAMW+6QYIUiuHy9rzm9QjOjtBsYpuxZOJmgEn3SUYG+CmGcZ5MkL1EcIVXK8Zj8+MUhK8DzBLgg4RLc3cOMNSr4yHNDMJu2Glenw0RBy1cTiznoVFShGPe8btlhFoZEOG9RmVHHY92bQHlXQ4rausTS33+kwpC76/Cu6cMsaIPhX0oWyTVL/oN0PRcqIXh/0wwweuGxZGwlVdQss43hrWLQMnlyPU58Mz198ikMejRxyvzI6VB1hdYHSGaCdefH/hLzZDIfnrFSeUw7/MVsMfPrL6K0vhX1gAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/1ce6b542d9bfcd892553b9d732fab0d6/ca1dc/2.png&apos; srcset=&apos;/static/1ce6b542d9bfcd892553b9d732fab0d6/e7570/2.png 170w,
/static/1ce6b542d9bfcd892553b9d732fab0d6/f46e7/2.png 340w,
/static/1ce6b542d9bfcd892553b9d732fab0d6/ca1dc/2.png 680w,
/static/1ce6b542d9bfcd892553b9d732fab0d6/02d09/2.png 1020w,
/static/1ce6b542d9bfcd892553b9d732fab0d6/9d567/2.png 1360w,
/static/1ce6b542d9bfcd892553b9d732fab0d6/c371b/2.png 1654w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;[해결]&lt;/h2&gt;
&lt;p&gt;요구사항 자체를 변경하거나, Spring에서 제공하는 file 매핑 기술을 사용하지 못한다. 그래서 요청을 다음과 같이 정의하고 Argument Resolver에서 Native한 Request를 받아서 직접 매핑해주기로 했다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1e1d8fbef09ddc42629867b6d769aebc/bb51b/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 92.94117647058823%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAACXBIWXMAABYlAAAWJQFJUiTwAAACmElEQVR42q2U2U5iQRCGW0BBkVXAhUVZBURkE5ElEY1cES7ECETineHCC96Dt/LJavxq5hBnyWRMhqToPt21/PVXVRtjjFiysbGh6/7+vtzc3Ei73ZZGo6HS7Xal2WzK+fm5vL6+Sjqd/snmk5hfD8Rms8nOzo64XC7Z2toSu90uTqdT98j29rY4HA519ll+c/iHaF8StefP5/OJx+ORfD4vvV5POp2ODAYDOTs70/NgMKioQXVwcCCxWEyOjo4kGo2uV87IyqCYSqUkl8upw9PTUykUCnJ5eSnFYlGSyaTyBgLuSqWSxONxyWQyeseKPXu4NpubmxIKhcTr9Yrf79cV2d3dVXSgDwQCyiEB4A89q1gEBh0BAWWA2+/3NTIpIuzL5bJUq1Vdr66upFKpKBqCYex2uzVFAgCKM+4NnAA5HA4rItCyZ4UfizOiY4AOxoB4enqSh4cHRb92SM+BKpFI6IGVKnwRiDO4pS+Hw6HU63U5OTmR1Wol/N7f39cOs9nsd4RsIpGIpoEDigJCiAYttFxcXEghX1Bn3APi7e1N7u/v122zTpmup3JwgjLcHR4efhiV1CHfTArO0LH0arWacgxqukWnx0KIA9IFCdUDMUY4JP3FYqGpw+v8+VnRX19fqx18wjF6yiGeuSAyaFqt1toR9+zn87mmSCGo+HQ61QFgEEajkbbPbDYTQ0Q+iEg1USYVgrCnMAR5fHyU5XIp4/FYbm9v1SGBeTDu7u7UhqIZUNGwx8fH6oRqwycB2MMblEAHTkE5mUx0NPm2mppe1Cr/89B/rASsVWvKJ83/8vKiVFl6cGys5+pvwvOFnqZfqWobgcaad9qFeYci89Unil7d29vT+YYG5prXiJH8EdjI/xKo+QYOrvjhJsvZTgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/1e1d8fbef09ddc42629867b6d769aebc/ca1dc/3.png&apos; srcset=&apos;/static/1e1d8fbef09ddc42629867b6d769aebc/e7570/3.png 170w,
/static/1e1d8fbef09ddc42629867b6d769aebc/f46e7/3.png 340w,
/static/1e1d8fbef09ddc42629867b6d769aebc/ca1dc/3.png 680w,
/static/1e1d8fbef09ddc42629867b6d769aebc/02d09/3.png 1020w,
/static/1e1d8fbef09ddc42629867b6d769aebc/bb51b/3.png 1320w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;multipart/form-data는 name을 key(unique할 필요 없음) data를 value로 하는 테이블 형식과 비슷하다. 그래서 요청을 다음과 같이 받을 수 있다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;jsonData라는 name으로 피드 생성에 필요한 데이터를 받는다.&lt;/li&gt;
&lt;li&gt;각 단계의 이름을 name으로 사진 파일을 받는다. name이 같을 경우 해당 단계의 다른 사진으로 인식하여 한 단계의 여러개의 사진을 받을 수 있다. 만약 0개의 사진을 가지고있는 단계의 경우(위 사진의 step2), 그냥 해당 단계를 name으로 가지는 열을 만들지 않으면 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;그리고 Arument Resolver에서 원하는 객체 형태로 매핑을 해주고, handler로 넘겨주면 된다. &lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ffc12d8a6775b71f847bf029adbfda07/c7953/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 62.94117647058823%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAACLElEQVR42m2T2VbcMBBE+ZcEMt5l7YvXGZsBHvj/v6mUPJNAIA/3WG0ft9RVpYd1njENM4ZxhJAeVatRNpY4ri3q7l9Kfq+lQ6P8ndu67AyKxuBBixnOjIgxwocI4wKMTDDdAilZ2wBtwt9npyz8PiO+kOuMcJ0wvC3ovMep0njwYoNrN6QwIg0JUQSkLqBpDZ5KdaNSn9YaT4X8qDOsf1V5Mp5Q8LitYgNJOq4FRyVF61ALj6LjmhLkuuTIFevMqdY4NZ9gfYw8hw2T2+HjDpVeIKc3aL/DOo40TkhpgHcRzkZq6I6fTrW5NfzC0bCsPUSbIHruTu1KvaBWEzo9QJgB1mb9PBT1bClFUSv+qD/42lDogLqnW/xBKJ5CWOoh8fPU31H4UWQkHvk+6/l4aKdv2pKsX+ZoOLj1cLc1Mxq7QbgLnDwjpoSBJjnnkZxFyKfVTIMfMGbzmIrARGQko1PTxMOUojKw/YIxkYkRoG5TuuB6WfC8LwgxIXhqaDwMzdNygAkTmaHcgJ6Z7ClXK+4NhVyQ5ncs+xXPzzumeYGyCdIkGjUfGJqitaM5OYsOnZ1uE5Gn+h6lPyN3LV3kh/M6YV3yjeEGvDkurjzFChvP6NlcxQtk3JiEDZrfer9Chst3lxuR0IdXqOUdw3KFT2zgL7Aj18MZjnUcN0g70rzAjPrj2dLEirn81rDinW06xqW/ww0qPis58ppFktDlyMhw1A0Tkev8vv5Pw9/udKIuuiYRZQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;FeedSaveArgumentResolver.java&apos; title=&apos;&apos; src=&apos;/static/ffc12d8a6775b71f847bf029adbfda07/ca1dc/4.png&apos; srcset=&apos;/static/ffc12d8a6775b71f847bf029adbfda07/e7570/4.png 170w,
/static/ffc12d8a6775b71f847bf029adbfda07/f46e7/4.png 340w,
/static/ffc12d8a6775b71f847bf029adbfda07/ca1dc/4.png 680w,
/static/ffc12d8a6775b71f847bf029adbfda07/02d09/4.png 1020w,
/static/ffc12d8a6775b71f847bf029adbfda07/9d567/4.png 1360w,
/static/ffc12d8a6775b71f847bf029adbfda07/c7953/4.png 1896w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;FeedSaveArgumentResolver.java&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;실제로는 더 복잡하게 동작을 하지만 본 메소드는 위와 같다.&lt;/p&gt;
&lt;p&gt;controller 부분은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6fcfd295a4316338c5924195de21802f/d4fa6/5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 21.176470588235293%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAYAAACOXx+WAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA1ElEQVR42h2PW66DMAxE2UwplHcgcUJKoKKouvtf0LkOHyN7jkZ+FBICcYuID5jZ0Y/C7DzGCpP6aRblwmi0XzztFGkGz2v0VL3l0cyUqkezaF0oUji5ji/XmQhxw/mVxa5M7oMbE+Ki8jchrFjrmXVozojXpSYyDRvGZS50k6WoWyGMP1LcOa+TlHaCfNjij8PvmPiHPy8+14FbI/GtzG+MkuiNULeOl16aVXV6YdUvVG02llr7WmHZO563LGXnuDOD+i7nnOYyk3tA2c73q1nPduEf2lCAwLbwIZAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;FeedController.java&apos; title=&apos;&apos; src=&apos;/static/6fcfd295a4316338c5924195de21802f/ca1dc/5.png&apos; srcset=&apos;/static/6fcfd295a4316338c5924195de21802f/e7570/5.png 170w,
/static/6fcfd295a4316338c5924195de21802f/f46e7/5.png 340w,
/static/6fcfd295a4316338c5924195de21802f/ca1dc/5.png 680w,
/static/6fcfd295a4316338c5924195de21802f/02d09/5.png 1020w,
/static/6fcfd295a4316338c5924195de21802f/9d567/5.png 1360w,
/static/6fcfd295a4316338c5924195de21802f/d4fa6/5.png 1598w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;FeedController.java&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h2&gt;[정리]&lt;/h2&gt;
&lt;p&gt;요청 자체가 복잡한 API를 Argument Resolver에서 Native한 Request를 직접 만져서 해결할 수 있다. 요청이 복잡하더라도 겁먹지 말고 Argument Resolver를 적극 활용해보자.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[JWT 토큰에 대해서 알아보자]]></title><description><![CDATA[들어가며 이번 프로젝트를 진행하면서 토큰을 이용한 인증/인가에서 jwt를 사용하게 되었다. 그 과정에서 알게된 jwt의 특성과 경험을 기록하기 위해 이 글을 쓰게 되었다. JWT란? JWT는 JSON Web Token의 줄임말로, 두 개체(ex…]]></description><link>https://hoonblog.netlify.app/json-web-token/</link><guid isPermaLink="false">https://hoonblog.netlify.app/json-web-token/</guid><pubDate>Wed, 06 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;이번 프로젝트를 진행하면서 토큰을 이용한 인증/인가에서 jwt를 사용하게 되었다. 그 과정에서 알게된 jwt의 특성과 경험을 기록하기 위해 이 글을 쓰게 되었다.&lt;/p&gt;
&lt;h2&gt;[JWT란?]&lt;/h2&gt;
&lt;p&gt;JWT는 JSON Web Token의 줄임말로, 두 개체(ex -&gt; 서버와 서버) 사이에 정보를 안전하게 전송하기 위한 토큰 인증 방법이다. 이는 RFC 7519에 정의 되어있고 토큰 인증 방식에서 많이 사용되는 방법이라고 볼 수 있다.&lt;/p&gt;
&lt;p&gt;jwt가 안전한 이유는 jwt토큰 자체가 디지털 서명이 되어있기 때문이다. 비밀키를 알고있어야 jwt가 유효한지 알 수 있기 때문에 중간에 토큰이 오염이 되지 않았음을 보장할 수 있다.&lt;/p&gt;
&lt;h2&gt;[JWT 토큰 구조]&lt;/h2&gt;
&lt;p&gt;JWT는 Header, Payload, Signature로 나눠진다. 각각에 대해서 알아보자.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Header&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;헤더는 일반적으로 토큰 유형(JWT)과 사용 중인 서명 알고리즘 두 부분으로 구성된다. 토큰 전체의 메타 정보 같은 느낌으로 다른 정보가 추가적으로 들어갈 수 있다. 이 부분은 단순히 Base64Url을 사용해서 인코딩 되어있다. 그래서 어디서든지 디코딩이 가능하다. 그러므로 민감한 정보가 들어가면 안된다. jwt.io에서 헤더를 복호화 시켜보면 다음과 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Payload&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;페이로드는 토큰의 두 번째 부분으로 클레임을 포함한다. 클레임은 엔티티(일반적으로 사용자) 및 추가 데이터에 대한 설명이다. 클레임에는 등록, 공개, 비공개 클레임 세 가지 유형이 있다. 보통 토큰이 발행한 주체(issuer), 토큰의 수신자(recipient), 토큰의 발행시간, 토큰의 만료시간 등이 포함된다.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;등록된 클레임 : 등록된 클레임은 유용하게 클레임을 제공하기 위해 권장되는 클레임 집합이다. 필수는 아니지만 jwt 토큰을 유용하게 쓰려면 이 정도 클레임은 포함하라고 하는 권장 사항 정도이다. 구성 요소는 다음과 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;- iss: 토큰 발급자 (issuer)
- sub: 토큰 제목 (subject)
- aud: 토큰 대상자 (audience)
- exp: 토큰의 만료시간 (expiraton)
- nbf: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념
- iat: 토큰이 발급된 시간 (issued at)
- jti: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지를 위한 목적&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;공개 클레임 : JWT 사용자에 의해 정의될 수 있는 클레임의 집합이다. 충돌되지 않는 이름을 가지고 있어야하며, 이를 위해서 IANA JSON 웹 토큰 레지스트리에 정의하거나 충돌 방지 네임스페이스를 포함하는 URI로 정의해야 한다. 즉, JWT 사용자들 사이의 약속이다.&lt;/li&gt;
&lt;li&gt;비공개 클레임 : 양 측간에 (보통 클라이언트 &amp;#x3C;-&gt;서버) 협의하에 사용되는 클레임 집합이다. 공개 클레임과는 달리 이름이 중복되어 충돌이 될 수 있으니 사용할때에 유의해야한다. 토큰에서 제공할 추가적인 정보를 줄때 이용된다.
payload 또한 Base64Url로 인코딩 되어있기 때문에 민감한 정보를 포함하면 안된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Signature&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;시그니처는 마지막 부분으로 디지털 서명을 담당한다. 이 서명은 헤더의 인코딩값과, 정보의 인코딩값을 합친후 주어진 비밀키로 해쉬를 하여 생성합니다. 비밀키가 있어야만 이 부분을 풀 수 있으며, 비밀키는 서버에서 안전하게 보관되어야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;[JWT를 이용한 인증/인가 방식]&lt;/h2&gt;
&lt;p&gt;JWT를 이용한 인증/인가 방식에는 여러가지가 있지만 가장 일반적인 방식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b616c27a6c0909790ed7b0a1cc40e935/bbbf7/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 64.70588235294117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAABtElEQVR42n1T127CQBDkY/kl/oOXSDxEoomqSGBseu+92AREaJOdTYwgmKy0Emv25mZm93z4jev1inw+j2azeav/hvutWq2i1Wp59vnum7PZLOr1Os7nMy6Sm80G7XYb0+kUp9MJx+NRe3u9Hmaz2WvAy+WiRSqVgmVZCjAajRScrC3TxHA4xGAwwGKxQDgc1to9S1AX+AGQDOfz+e226XiMj3QKZi53O8goFArK3CseADOZDLrdLjqdDgwjj3K5In7VUK1UYApT5ud2q3302nEc9Pt9BZ9MJs+A6XQaxWJR/6Q8AvNbTYZAifRuuVwiEomoJapC7KHXngwpmR69mrLbR8m80A3LMuH3+2Hb9rNksmAahoGKSK3VfiRbUjP3+7323QNSfiAQwG63ewYkCGVRyliGQgsodyY1rbBFXiwWU8lcJYJxkPzt6WGj0YAjxtOXvrAgIBd5vVphJUkWiURCV4ps2cfL1+u1t4dsZNNG/DDFq7dgEO+hkLKgv5xsMpm8Sf53sUNy0H16jK/DAbbc7Ag4D7p90WhUB8Pgq3q52PF4XCXfv4D7p8nDrpJSqeTJ8BtOEtML0w+40gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/b616c27a6c0909790ed7b0a1cc40e935/ca1dc/1.png&apos; srcset=&apos;/static/b616c27a6c0909790ed7b0a1cc40e935/e7570/1.png 170w,
/static/b616c27a6c0909790ed7b0a1cc40e935/f46e7/1.png 340w,
/static/b616c27a6c0909790ed7b0a1cc40e935/ca1dc/1.png 680w,
/static/b616c27a6c0909790ed7b0a1cc40e935/02d09/1.png 1020w,
/static/b616c27a6c0909790ed7b0a1cc40e935/bbbf7/1.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;적절한 회원이 로그인 요청을 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;서버에서는 회원의 정보(id, password)가 적절한지 확인하고, 적절하다면 RefreshToken과 AccessToken을 발행한다.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;로그인된 회원만 사용할 수 있는 API인 경우 Authentication Header에 AccessToken을 담아서 보낸다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;서버에서는 이 토큰이 유효한지 확인만 진행한다. 토큰 자체로 유효성 검사를 할 수 있기 때문에 DB를 가져온다는 등의 수고는 안해도 된다.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;AccessToken 토큰이 만료되었을 경우 RefreshToken으로 재발행을 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;AccessToken이 만료되었을 경우, RefreshToken을 서버로 전달하여 AccessToken과 RefreshToken을 재발행한다. 만약 RefreshToken이 유효하다면 사용자는 토큰들을 재발행 받을 것이다. &lt;/p&gt;
&lt;p&gt;이때, RefreshToken은 DB 시스템에 저장을 한다. RefreshToken은 단순히 유효함을 확인하는 것이 아니고 따로 저장을 해두어서 사용을 한다. &lt;/p&gt;
&lt;p&gt;인증 방식은 Session 인증 방식과 비슷하다. 차이가 있다면 AccessToken을 활용함으로써 DB와 연결되는 네트워킹 횟수가 주는 것이다. 만약 유효하지 않다면 401을 던진다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[CS] SHA-256 + Salt]]></title><description><![CDATA[들어가며 프로젝트를 진행하며 SHA-256 단방향 암호화를 진행하면서 발생하는 문제점을 인식하고 해결한 과정에 대해 기록하고자 이 글을 쓰게되었다. SHA-256이란? SHA-256은 SHA-2(Secure Hash Algorithm…]]></description><link>https://hoonblog.netlify.app/sha-256/</link><guid isPermaLink="false">https://hoonblog.netlify.app/sha-256/</guid><pubDate>Wed, 06 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;프로젝트를 진행하며 SHA-256 단방향 암호화를 진행하면서 발생하는 문제점을 인식하고 해결한 과정에 대해 기록하고자 이 글을 쓰게되었다.&lt;/p&gt;
&lt;h2&gt;[SHA-256이란?]&lt;/h2&gt;
&lt;p&gt;SHA-256은 SHA-2(Secure Hash Algorithm 2)의 한 형태로, 암호학적 해시 함수의 집합 중 하나이다. 여기서 256은 이 알고리즘이 생성하는 해시 값의 비트 길이이다.
암호학적 해시 함수란 임의의 크기를 입력 받아 그 길이의 고유한 문자열로 변환하는 함수이다. 암호학적 해시 함수는 다음과 같은 특징을 가지고 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Preimage resistance (원상 저항성): 해시 결과(해시 값)로부터 원래의 입력 값을 찾아내는 것이 불가능하다. 즉, 해시 값만 가지고는 원래 데이터를 알아낼 수 없다.&lt;/li&gt;
&lt;li&gt;Second preimage resistance (제2원상 저항성): 주어진 입력 값에 대해 동일한 해시 값을 생성하는 다른 입력 값을 찾아내는 것이 어렵다.&lt;/li&gt;
&lt;li&gt;Collision resistance (충돌 저항성): 두 개의 임의의 다른 입력 값이 동일한 해시 값을 생성하는 것, 즉 충돌이 발생하는 것이 어렵다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;위의 특징 때문에 고유하고 안전해서 단방향 암호화에서 많이 사용된다. 하지만 SHA-256도 뚫릴 수 있는 가능성이 있다.&lt;/p&gt;
&lt;h2&gt;[SHA-256의 약점]&lt;/h2&gt;
&lt;p&gt;해시 함수는 어쩔 수 없이 동일한 입력에 대해 항상 동일한 출력을 생성한다. 즉, 누가 암호화하던 동일한 입력이라면 동일한 출력이라는 것이다.
이러한 약점을 활용해서 해커들은 SHA-256를 통해 생성된 해시 값을 따로 저장해두고, 일치하는 값을 확인한다. 이를 &lt;code class=&quot;language-text&quot;&gt;레인보우 테이블&lt;/code&gt;이라고 한다.&lt;/p&gt;
&lt;h3&gt;레인보우 테이블(Rainbow Table)&lt;/h3&gt;
&lt;p&gt;레인보우 테이블은 암호학적 해시 함수를 통해 생성된 해시 값을 역으로 추척해서 원래의 데이터(일반적으로 패스워드)를 찾아내기 위한 방법 중 하나이다.&lt;/p&gt;
&lt;p&gt;레인보우 테이블은 미리 계산된 해시 값과 그에 해당하는 원래의 데이터를 대응시킨 테이블을 의미한다. 이 테이블은 많은 양의 디스크 공간을 차지하지만, 빠르게 해시 값을 &apos;크래킹&apos;할 수 있게 해준다. &lt;/p&gt;
&lt;p&gt;사람이 하나하나 확인하는 것은 어렵지만 이를 컴퓨터로 진행한다면 금방 찾을 것이다. 그렇다면 이에 대한 대응책은 뭘까?&lt;/p&gt;
&lt;h2&gt;[대응책 - Salting]&lt;/h2&gt;
&lt;p&gt;솔팅(Salting)은 암호화된 정보, 특히 사용자의 비밀번호에 추가적인 무작위 데이터를 더하는 방식을 말한다. 이 추가적인 데이터는 &apos;솔트(Salt)&apos;라고 부르며, 해시 함수에 들어가는 입력값을 변경해 해시 결과를 달리하는 역할을 한다.
이렇게 되면 레인보우 테이블에 대한 공격을 거의 대부분 방어할 수 있다.&lt;/p&gt;
&lt;p&gt;하지만 솔팅의 단점은 사용자에 대한 솔트를 서버가 가지고있어야한다. 즉, 서버는 암호화된 비밀번호와 솔트 모두 가져야한다. 그만큼 비용이 크다는 것이다.&lt;/p&gt;
&lt;p&gt;솔팅은 패스워드의 보안성을 향상시키는 매우 좋은 방법이다. 하지만 당연하게도 솔팅만으로는 충분하지 않으며, 다른 보안 조치와 함께 사용한다. 예를 들어, 강력한 해시 알고리즘을 사용하거나, 해시를 여러 번 적용하는 등의 방법 등이 있다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[우테코] 프리코스 4주차 회고]]></title><description><![CDATA[4주 차 온보딩 github…]]></description><link>https://hoonblog.netlify.app/wooteco-free-4/</link><guid isPermaLink="false">https://hoonblog.netlify.app/wooteco-free-4/</guid><pubDate>Mon, 20 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.35294117647059%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAckEgn//xAAXEAEAAwAAAAAAAAAAAAAAAAABABAR/9oACAEBAAEFAjIpX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABcQAAMBAAAAAAAAAAAAAAAAAAAQITH/2gAIAQEABj8Cpi//xAAZEAACAwEAAAAAAAAAAAAAAAARQQABEIH/2gAIAQEAAT8hZQxQe5//2gAMAwEAAgADAAAAEIvf/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8QZ//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAgEBPxARf//EABgQAAMBAQAAAAAAAAAAAAAAAAABEVEx/9oACAEBAAE/EJOhMsGVLdtj6f/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg&apos; srcset=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/0b705/1.jpg 170w,
/static/a99ed4151ee311be6b774d7b6e8431ff/31389/1.jpg 340w,
/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/donghoonyeom/java-christmas-6-donghoonyeom&quot;&gt;4주 차 온보딩 github&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;이번주 미션은 처음 보는 형태의 미션이었다. 이메일 형태의 미션이어서 현업에서 개발자가 받을 수 있을 만한 내용의 메일이기도 하고, 내가 진짜 현업에서 일하고 있는 개발자가 된것 같은 기분이 들게 되는 미션이어서 매우 흥미로웠다. 이번 주의 목표는 저번주와 비슷한 클래스(객체)를 분리하는 연습을 조금 더 해보는 것이 었다. 저번주에 진행한 과제에서 생각해보면 단일 책임 원칙이나, 모듈화나 응집성을 높이지 못한것 같아 아쉬운 부분이 많았는데 이번 주도 같은 목표이다보니 더 연습해 볼 수 있어서 좋았던 것 같다. 미션을 받고 가장 먼저 한 일은 이번 주도 역시 3주차 공통 피드백을 확인했다.&lt;/p&gt;
&lt;h2&gt;[연관성이 있는 상수는 static final 대신 Enum을 활용한다.]&lt;/h2&gt;
&lt;p&gt;가장 먼저 눈에 들어온 것은 “연관성이 있는 상수는 &lt;code class=&quot;language-text&quot;&gt;static final&lt;/code&gt; 대신 &lt;code class=&quot;language-text&quot;&gt;Enum&lt;/code&gt;을 활용한다.”라는 내용이었다. 저번 주는 로또의 등수를 &lt;code class=&quot;language-text&quot;&gt;Enum&lt;/code&gt;을 활용했었는데, 이번 주 미션에서는 연관성이 있는 상수가 어떤게 있을지 고민해 보았다. &lt;/p&gt;
&lt;p&gt;가장 먼저 떠오른 부분은 메뉴였다. 메뉴 &lt;code class=&quot;language-text&quot;&gt;Enum&lt;/code&gt;을 사용하여 메뉴와 가격을 관리하는 것은 가독성과 유지보수성을 향상시킬 수 있었고, 메뉴의 가격은 &lt;code class=&quot;language-text&quot;&gt;Enum&lt;/code&gt; 내부에서 적절하게 캡슐화되어 있어서, 외부에서 직접 변경이 어렵게 된다. &lt;/p&gt;
&lt;p&gt;또 어떤 부분이 &lt;code class=&quot;language-text&quot;&gt;Enum&lt;/code&gt;으로 될 수 있을지 고민해 보았는데, &lt;code class=&quot;language-text&quot;&gt;Badge&lt;/code&gt; 와 &lt;code class=&quot;language-text&quot;&gt;ErrorMessage&lt;/code&gt; 부분을 만들어 보았다. 모두 값이 자주 변하지 않고, 연관성이 있다고 생각해서 만들었다. 만들어 보니 확실히 가독성이 많이 좋아지고, &lt;code class=&quot;language-text&quot;&gt;Enum&lt;/code&gt;은 클래스로 정의되기 때문에 내부에 작은 기능을 하는 메서드를 만들어 사용해 보니 단순한 상수 그룹 이상의 기능을 만들 수 있다고 느꼈다.&lt;/p&gt;
&lt;h2&gt;[테스트 코드도 코드다.]&lt;/h2&gt;
&lt;p&gt;다음 인상 깊었던 부분은 “테스트 코드도 코드다”라는 내용이었다. 테스트 코드가 중요하다는 말은 익히 들어서 알고 있었지만, 나는 우테코 이전에 테스트 코드를 작성해 보지 않았다. &lt;/p&gt;
&lt;p&gt;일단 가장 큰 이유는 어떻게 작성해야할 지 감이 잡히지 않는 것이었다. 혼자 블로그나 강의를 보며 작성해봤지만, 쉽지 않았던 기억 때문에 습관이 안된것 같다. 하지만 우테코 프리코스를 시작한 이후로 테스트 코드를 작성해보고, 확실히 많은 것을 느낄 수 있었다. &lt;/p&gt;
&lt;p&gt;가장 좋은 점은 테스트 코드를 작성 후에 코드 리팩토링을 하다보면 거침 없이 할 수 있다는것이다. 전에 테스트 코드를 작성하지 않고, 리팩토링을 진행 할 때는 코드를 작성하면서 많이 망설이던 모습이 떠오른다. 이걸 고쳤다가 안되면 어떡하지? 라는 생각을 가장 많이 했던 것같다. &lt;/p&gt;
&lt;p&gt;하지만 지금은 테스트 코드를 작성 하다보니, 확실히 코드에 문제가 있더라도 어떤 부분에서 문제가 생겼는지, 빠르게 알아차릴 수 있고, 더 나아가 유지보수성이 많이 좋아진다고 느낀다. 돌아와서 “테스트 코드도 코드다.” 부분에서는 테스트 코드의 리펙토링의 중요성을 보여주고 있었다. 특히 이번 주도 저번 주에 공부 했던 &lt;code class=&quot;language-text&quot;&gt;@ParameterizedTest&lt;/code&gt; 와 &lt;code class=&quot;language-text&quot;&gt;@ValueSource&lt;/code&gt; 를 사용해서 단순히 파라미터의 값만 바뀌는 경우를 처리해 주려고 노력했고, 가독성이 좋은 테스트코드를 작성하기 위해 노력했는데, 아직 많이 어려운것 같아 꾸준한 연습이 필요할 것 같다.&lt;/p&gt;
&lt;h2&gt;[단위 테스트하기 어려운 코드를 단위 테스트하기]&lt;/h2&gt;
&lt;p&gt;이번에 &lt;code class=&quot;language-text&quot;&gt;Order&lt;/code&gt;라는 클래스를 생성하면서 &lt;code class=&quot;language-text&quot;&gt;createOrder&lt;/code&gt; 메서드를 테스트하려고 했는데 &lt;code class=&quot;language-text&quot;&gt;InputView.getOrder()&lt;/code&gt;와 &lt;code class=&quot;language-text&quot;&gt;printPreviewPhrase&lt;/code&gt;를 직접 호출 하고, 테스트 불가능한 정적 메서드 호출로 인해 단위 테스트가 쉽지않았었다. &lt;/p&gt;
&lt;p&gt;리팩토링하여 &lt;code class=&quot;language-text&quot;&gt;createOrder&lt;/code&gt; 메서드가 외부 의존성을 직접적으로 호출하지 않게 되었고, 대신, &lt;code class=&quot;language-text&quot;&gt;createOrderItems&lt;/code&gt; 내에서 필요한 의존성을 주입받아 사용하도록 바꿨다. 입력 및 출력 동작은 &lt;code class=&quot;language-text&quot;&gt;InputView&lt;/code&gt;와 &lt;code class=&quot;language-text&quot;&gt;OutputView&lt;/code&gt;에 캡슐화되어 있고, 테스트에서는 이를 &lt;code class=&quot;language-text&quot;&gt;Mock&lt;/code&gt;으로 대체하여 특정 입력값과 출력값을 쉽게 테스트할 수 있게 바꿨다. &lt;/p&gt;
&lt;p&gt;주문 생성 및 관련된 동작들이 각자의 클래스에 모듈화 했기 때문에, 특정 기능을 수정할 때 다른 부분에 영향을 미치지 않도록 하였고, 안전하게 변경할 수 있게 되었다. 특히, &lt;code class=&quot;language-text&quot;&gt;createOrderItems&lt;/code&gt; 메서드에서 OrderItem 클래스를 사용하여 주문 항목을 캡슐화 하면서 유닛 테스트가 더 쉬워질 수 있었다. &lt;/p&gt;
&lt;p&gt;정적 메서드 사용을 최소화하고 의존성 주입을 통해 테스트 가능한 코드를 작성하는 중요성을 깨닫게 되었고, 코드의 신뢰성을 향상시키고 유지 보수를 용이하게 만들기 위해 코드를 작성할 때부터 테스트 가능성을 고려하는 것이 중요하다고 생각된다.&lt;/p&gt;
&lt;h2&gt;[클래스(객체)를 분리하는 연습]&lt;/h2&gt;
&lt;p&gt;저번주 미션에서도 클래스를 분리하여 비지니스 로직과 UI로직을 분리해서 코드를 작성했지만, 이번주는 더 작게 나누려고 노력해봤다 출력을 담당하는 &lt;code class=&quot;language-text&quot;&gt;OutputView&lt;/code&gt; 에서 주문 정보를 출력하는 &lt;code class=&quot;language-text&quot;&gt;OrderOutputPrinter&lt;/code&gt;와 할인 정보를 출력하는 &lt;code class=&quot;language-text&quot;&gt;DiscountOutputPrinter&lt;/code&gt;로 나누어 주었고, &lt;code class=&quot;language-text&quot;&gt;Order&lt;/code&gt; 클래스에서 메뉴 이름과, 수량을 담는 &lt;code class=&quot;language-text&quot;&gt;OrderItem&lt;/code&gt; 클래스도 나누려고 노력했다.&lt;/p&gt;
&lt;p&gt;다른 클래스들도 최대한 단일 책임원칙에 맞게 분리하려고 노력했다. 클래스를 분리함으로써 각 클래스는 자체적인 역할을 수행하게 되어 응집도가 높아졌고, 각 클래스는 특정 기능이나 역할을 담당하므로 코드를 이해하고 유지보수하기가 훨씬 쉬워진것 같았다.&lt;/p&gt;
&lt;p&gt;또 단위테스트를 작성하면서 각 클래스는 독립적으로 테스트할 수 있기 때문에 특정 기능에 대한 테스트 케이스를 간편하게 작성 할 수 있었다. 하지만 클래스를 분리하면 각 클래스 간의 의존성을 적절히 관리해야 할 것 같았다. 너무 많은 의존성이 발생하면 결합도가 높아져서 코드 변경이 어려워질 것 같고, 처음에 많은 시간이 소요 되서 많은 연습이 필요할 것 같다.&lt;/p&gt;
&lt;h2&gt;[프리코스 4주 후 느낀점]&lt;/h2&gt;
&lt;p&gt;프리코스를 진행하며, 내가 부족한 부분에 대해서 더 자세히 알게된 것 같다. 지금까지 개발을 공부 하면서 이런 온보딩 형식의 미션을 접할 기회가 많이 없어서 처음에는 어색하기도 하고, 어려움을 많이 느꼈지만 이제는 “이런식으로 공부하면 정말 빠르게 성장 할 수 있겠구나!” 라는 생각이 든다. &lt;/p&gt;
&lt;p&gt;정말 재미있게 몰입할 수 있었고, 타 교육을 진행한 5개월 보다 많은 양을 배울 수 있었던 시간이었다고 확실히 알 수 있었다. 프리코스를 진행하면서 우테코 본 과정에서는 얼마나 많은걸 배울 수 있을까? 라는 생각과 함께 우테코에 대한 열망이 더 많이 생겼다.&lt;/p&gt;
&lt;h3&gt;이후 목표&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;- TDD의 가치를 더 깊이 이해하고, 새로운 기능을 추가하거나 기존 코드를 리팩토링할 때 테스트 코드를 우선 작성하도록 연습해야한다. 이를 통해 안정적이고 견고한 코드를 작성하는 습관을 들여야한다.
- 코드의 가독성과 유지보수성을 높이기 위해 꾸준한 노력을 기울여야한다. 가독성이 좋고 간결한 코드 작성을 위해 코드 리뷰와 연습 통해 더 많은 클린 코드 습관을 습득하고 적용해야 한다.
- 객체지향 프로그래밍의 원칙과 패턴에 대한 학습을 지속하고, 실제 프로젝트에서 이를 적용해보려고 한다. 클래스 설계와 객체 간의 관계를 더욱 효과적으로 다루기 위해 노력하여 코드의 유연성과 확장성을 향상 시켜야한다.
- 블로깅을 통해 지식을 공유하며 함께 성장하는 기회를 더욱 많이 찾아봐야한다. 다양한 의견, 경험을 공유하고, 다른 개발자들과 소통하며 성장의 기반을 다지려고한다.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[우테코] 프리코스 3주차 회고]]></title><description><![CDATA[3주 차 온보딩 github…]]></description><link>https://hoonblog.netlify.app/wooteco-free-3/</link><guid isPermaLink="false">https://hoonblog.netlify.app/wooteco-free-3/</guid><pubDate>Fri, 10 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.35294117647059%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAckEgn//xAAXEAEAAwAAAAAAAAAAAAAAAAABABAR/9oACAEBAAEFAjIpX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABcQAAMBAAAAAAAAAAAAAAAAAAAQITH/2gAIAQEABj8Cpi//xAAZEAACAwEAAAAAAAAAAAAAAAARQQABEIH/2gAIAQEAAT8hZQxQe5//2gAMAwEAAgADAAAAEIvf/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8QZ//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAgEBPxARf//EABgQAAMBAQAAAAAAAAAAAAAAAAABEVEx/9oACAEBAAE/EJOhMsGVLdtj6f/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg&apos; srcset=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/0b705/1.jpg 170w,
/static/a99ed4151ee311be6b774d7b6e8431ff/31389/1.jpg 340w,
/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/donghoonyeom/java-lotto-6/tree/donghoonyeom&quot;&gt;3주 차 온보딩 github&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;처음 과제를 진행할 때 저번주에 진행했던 레이싱 게임에 비해서 확실히 난이도가 상승했다고 생각했다. 요구사항들이 꽤 추가 되어 있었고, 당연히 구현은 더 오랜시간이 걸렸다.저번주와 마찬가지로 테스트 코드를 미리 작성하는 TDD 방식은 아직 익숙 하지 않아 꾸준한 노력이 필요하다고 생각한다. 가장 먼저 피드백으로 제공해주신 내용을 확인하면서, &lt;a href=&quot;https://techcourse-storage.s3.ap-northeast-2.amazonaws.com/9b82d8a360c548fcadd14c551dbcbe06&quot;&gt;학습테스트를 통해 JUnit 학습하기&lt;/a&gt; 문서를 가장 먼저 읽어 보았고, 메일서 목표로 주어진 내용인 테스트코드와 리팩토링을 중점적으로 연습하려고 노력했다.&lt;/p&gt;
&lt;h2&gt;[도메인 로직에 대한 단위 테스트를 작성하는 연습]&lt;/h2&gt;
&lt;p&gt;가장 먼저 단위테스트를 작성하는 연습을 하기 위해서는 도메인 로직에 대한 단위 테스트가 무엇인지 파악하는게 먼저였다. 구글링과 GPT에 질문해보면서 어떤 내용의 테스트 인지 파악해본 결과 특정 함수, 또는 클래스와 같은 도메인 로직의 작은 부분에 대해 수행되는 테스트라는 설명이 많았다. 피드백과 함께 제공된 문서를 보며 String 클래스에 대해서 먼저 작성해보려고 나는 문자열 정수를 받았을 때 “,”로 &lt;code class=&quot;language-text&quot;&gt;split&lt;/code&gt;하고 &lt;code class=&quot;language-text&quot;&gt;List&lt;/code&gt;로 바꿔 주는 클래스를 만들어서 처음에는 &lt;code class=&quot;language-text&quot;&gt;assertEquals&lt;/code&gt; 로 비교해서 맞는지 검증해보았다. &lt;/p&gt;
&lt;p&gt;테스트 작성 연습을 위해 검증을 해보면서 &lt;code class=&quot;language-text&quot;&gt;assertEquals&lt;/code&gt; , &lt;code class=&quot;language-text&quot;&gt;containsExactly&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;contains&lt;/code&gt; 차이에 대해서 이해하는데 많은 도움을 받았고, 더불어 &lt;code class=&quot;language-text&quot;&gt;Set&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;Collection&lt;/code&gt;에 대한 테스트 공부를 하면서 진행했던 &lt;code class=&quot;language-text&quot;&gt;@ParameterizedTest&lt;/code&gt;를 사용하면서 &lt;code class=&quot;language-text&quot;&gt;@ValueSource&lt;/code&gt;를 함께 사용하면서 코드를 제거하고 한번에 많은 케이스를 테스트하는 과정에서 처음 사용해 보았는데 많은 도움이 되었다. &lt;code class=&quot;language-text&quot;&gt;@ValueSource&lt;/code&gt;에 대해서 알게된점은 매번 배열의 인수 하나를 메서드 매개 변수에 할당 한다. 예를 들어 &lt;code class=&quot;language-text&quot;&gt;@ValueSource(strings = { &quot;500&quot;, &quot;0&quot; })&lt;/code&gt; 이 경우 총 2번 전달한다. 또 &lt;code class=&quot;language-text&quot;&gt;short&lt;/code&gt;,&lt;code class=&quot;language-text&quot;&gt;byte&lt;/code&gt;,&lt;code class=&quot;language-text&quot;&gt;int&lt;/code&gt;,&lt;code class=&quot;language-text&quot;&gt;long&lt;/code&gt;,&lt;code class=&quot;language-text&quot;&gt;float&lt;/code&gt;,&lt;code class=&quot;language-text&quot;&gt;double&lt;/code&gt;,&lt;code class=&quot;language-text&quot;&gt;char&lt;/code&gt;,&lt;code class=&quot;language-text&quot;&gt;String&lt;/code&gt;,&lt;code class=&quot;language-text&quot;&gt;Class&lt;/code&gt; 유형만 전달할 수 있었고, 매번 테스트 메서드에 하나의 인수만 전달할 수 있었다. null을 인수로 전달할 수 없다는 정보도 알게 되었다. null을 인수로 전달 받기 위해서는 ValueSource가 아닌 NullSource를 이용해서 단일 null값을 전달 할 수 있다. 기본 데이터 유형의 경우는 null을 전달 받을 수 없기 때문에 &lt;code class=&quot;language-text&quot;&gt;EmptySource&lt;/code&gt;을 사용하여 빈 값을 전달 할 수 있다고 한다. &lt;/p&gt;
&lt;p&gt;많은 정보를 &lt;a href=&quot;https://www.baeldung.com/parameterized-tests-junit-5&quot;&gt;Guide to JUnit 5 Parameterized Tests&lt;/a&gt; 문서를 통해 알게 되었고, 더 많은 내용을 테스트 코드에 직접 적용해보기 위해 더 많은 공부가 필요하다고 느꼈다. 또 다른 테스트들을 진행하면서 수익률 계산에 맞지 않는 경우가 있어서 확인 해보니, 내 처음 코드에서는 총 상금에서 로또의 구입금액까지 빼고있어서 오류가 발생한 부분이 있었다. 단위 테스트로 작게 만들다 보니 작은 기능에서 문제가 생겼을 때 빠른 피드백을 받을 수 있었고, 어떤 기능에 문제가 생겼는지 한번에 알아보기가 편해진 것 같았다. 또 리팩토링을 진행하면서 한번 진행할 때 마다 한번씩 테스트 케이스가 정상적으로 통과하는지 확인하다보니 리팩토링중에도 오류가 발생하거나 원하는 결과가 나오지 않았을 때 테스트 코드로 인해 더 빠른 리팩토링을 경험 할 수 있었다.&lt;/p&gt;
&lt;h2&gt;[클래스(객체)를 분리하는 연습]&lt;/h2&gt;
&lt;p&gt;확실히 저번 주 미션에서도 진행했던 부분이어서 어떤식으로 분리하고 메서드를 줄일 수 있을지 생각하면서 코드를 작성하다 보니, 처음부터 작은 메서드를 만들려고 노력하고 있는 나를 확인 할 수 있었다. 그래도 구현을 마치고 보니 많은 요구사항에 맞지않는 코드들이 너무 많았고, 최대한 더 읽기 편하고 메서드가 하나의 기능만 수행하도록 만들고 싶었는데, 생각보다 어려운 부분이 많았다. &lt;/p&gt;
&lt;p&gt;특히 예외 처리 부분에서 재입력을 받다보니 &lt;code class=&quot;language-text&quot;&gt;while&lt;/code&gt;문 안에 &lt;code class=&quot;language-text&quot;&gt;try-catch&lt;/code&gt;문까지 들어가니까 정말 보기 힘들었다. 그래서 예외처리 메서드를 최대한 나누고 &lt;code class=&quot;language-text&quot;&gt;do-while&lt;/code&gt;문에서 예외처리메서드 안에 인수를 넣어서 보기 좋게 바꾸려고 노력했다. 상수 부분에서도 아직 어떤 부분을 상수로 만들어야 할지 감이 잘 잡히진않는다. 하지만 가장 많이 사용되고 있다고 느끼는 로또의 가격부분과 로또의 1~45 부분, 로또 숫자의 개수를 상수로 처리 해줬는데 확실히 가독성이 좋아졌고, 어떤 숫자인지 내 코드를 처음보는 사람도 알 수 있었다면 좋겠다는 생각으로 진행했다. 확실히 1주차 보다는 코드가 많이 좋아졌다고 느끼는데 공부하다보면 아직 많이 부족하고, 배울게 정말 많다고 느껴진다. 더 노력하는 4주차가 되었으면 좋겠다.&lt;/p&gt;
&lt;h2&gt;[개선 해야 할 점]&lt;/h2&gt;
&lt;p&gt;확실히 테스트 코드작성을 프리코스에서 처음 진행하다보니 나 스스로도 아직 많이 부족함이 느껴진다. 이번주 피드백에서 주어진 테스트 코드 학습 문서를 통해 조금 더 테스트 코드에 대해서 공부해봐야 할 것 같고, 리팩토링에서 메서드 분리나 클래스 분리도 어떻게 해야 좋은 코드가 될지 고민 해봐야한다. 4주차는 조금 더 성장한 코드를 작성 했으면 좋겠다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[우테코] 프리코스 2주차 회고]]></title><description><![CDATA[2주 차 온보딩 github 들어가며 저번주 1주차 과제를 제출 후, 많은 후회가 몰려왔다.  가장 먼저 우테코에서 제시한…]]></description><link>https://hoonblog.netlify.app/wooteco-free-2/</link><guid isPermaLink="false">https://hoonblog.netlify.app/wooteco-free-2/</guid><pubDate>Thu, 02 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.35294117647059%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAckEgn//xAAXEAEAAwAAAAAAAAAAAAAAAAABABAR/9oACAEBAAEFAjIpX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABcQAAMBAAAAAAAAAAAAAAAAAAAQITH/2gAIAQEABj8Cpi//xAAZEAACAwEAAAAAAAAAAAAAAAARQQABEIH/2gAIAQEAAT8hZQxQe5//2gAMAwEAAgADAAAAEIvf/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8QZ//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAgEBPxARf//EABgQAAMBAQAAAAAAAAAAAAAAAAABEVEx/9oACAEBAAE/EJOhMsGVLdtj6f/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg&apos; srcset=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/0b705/1.jpg 170w,
/static/a99ed4151ee311be6b774d7b6e8431ff/31389/1.jpg 340w,
/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/donghoonyeom/java-racingcar-6/tree/donghoonyeom&quot;&gt;2주 차 온보딩 github&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;[들어가며]&lt;/h2&gt;
&lt;p&gt;저번주 1주차 과제를 제출 후, 많은 후회가 몰려왔다. &lt;/p&gt;
&lt;p&gt;가장 먼저 우테코에서 제시한 2가지의 테스트는 통과할 수 있었다. 하지만 하나의 숫자의 힌트를 얻을 경우 하나의 볼 또는 스트라이크가 출력돼야 한다고 되어 있지만 내 코드에서는 볼과 스트라이크가 하나만 있어도 0 볼, 0 스트라이크와 같이 힌트가 필요하지 않은 부분도 함께 출력된다. &lt;/p&gt;
&lt;p&gt;미션 요구사항도 제대로 읽지 않고, 클린코드나 리펙토링, 테스트코드에 관심이 집중되어 있던 모습이 정말 바보같이 느껴지는 하루였다. 이번 프리코스를 포기해야 하나 고민도 해봤지만 아직 남은 프리코스 미션과 시간이 남아있었기도 하였고, &lt;/p&gt;
&lt;p&gt;정말 우테코가 정말 간절하기에 계속 진행해 보기로 했다. 진행하며 2주차 미션부터는 요구사항에 대해 더 명확히 분석해야겠다는 다짐을 하게 된 경험이었다.&lt;/p&gt;
&lt;h2&gt;[미션을 진행하기 전 가장 먼저 한 일]&lt;/h2&gt;
&lt;p&gt;일단 저번 미션도 그랬지만 역시 처음 해보는 내용이었다. 저번주 반성 내용을 상기하며, 가장 먼저 한 일은 1주차 공통 피드백을 읽어보며 내가 어떻게 흡수해야 할지 생각해 보는 시간을 가졌다. &lt;/p&gt;
&lt;p&gt;같은 실수를 반복하지 않기 위해 README에 적혀있는 요구사항을 빠짐없이 체크하려고 노력했다. 그리고 야구게임에 대해 더 고민해보고 싶어 숫자 야구 피드백강의를 시청하였다. &lt;/p&gt;
&lt;p&gt;시청하면서 클래스 변수, 인스턴스 변수, 상수에 대해서도 조금 더 쉽게 이해할 수 있었고, 멀게만 느껴졌던 객체지향 프로그래밍에 조금 가까워질 수 있었다.&lt;/p&gt;
&lt;h2&gt;[테스트 코드 작성]&lt;/h2&gt;
&lt;p&gt;이번주차의 목표는 함수를 분리하고, 각 함수별로 테스트를 작성하는 것이라고 한다. 가장 먼저 아직 테스트코드를 작성해 본 적이 없어서 메일에 안내되어 있는 대로 &lt;code class=&quot;language-text&quot;&gt;StringTest&lt;/code&gt;를 확인하였다. &lt;/p&gt;
&lt;p&gt;하지만 문제가 &lt;code class=&quot;language-text&quot;&gt;StringTest&lt;/code&gt; 코드를 봐도 완전히 이해하긴 어려웠다. 그래서 구글링, gpt를 통해 테스트코드에 대해서 공부를 진행했다. 테스트 코드를 먼저 작성하고 그다음에 실제 코드를 작성하는 개발 방법인 TDD로 코드를 작성해야 하나 고민해봤지만, 아직 테스트 코드도 작성하지 못하는데 먼저 작성한다는 일은 막막하다는 느낌이 들어서 기능 구현을 먼저 하고, 테스트 코드를 작성해 보았다. &lt;/p&gt;
&lt;p&gt;완전한 테스트코드를 작성한 것은 아니지만 내가 할 수 있는 선에서 작성하도록 노력해 보았다. &lt;code class=&quot;language-text&quot;&gt;private&lt;/code&gt; 메서드를 테스트할 때 오류가 발생하여 &lt;code class=&quot;language-text&quot;&gt;public&lt;/code&gt; 으로 메서드를 변경하려고 했는데 그것은 권장하지 않는 방법이라고 한다. 그래서 Wrapper 클래스를 만들어 캡슐화하여 테스트를 진행하게 되었다. &lt;code class=&quot;language-text&quot;&gt;Wrapper&lt;/code&gt; 클래스를 통해 유지보수성이 좋아졌고, 결합도도 낮아졌다고 느낄 수 있었고, mock 객체를 사용해서 테스트도 할 수 있었다.&lt;/p&gt;
&lt;h2&gt;[메서드 분리]&lt;/h2&gt;
&lt;p&gt;이번 미션에서는 1주차 미션에서 적용하지 못했던 MVC패턴을 적용해 보았다. 가장 먼저 &lt;code class=&quot;language-text&quot;&gt;controller&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;view&lt;/code&gt; 3개의 디렉터리를 생성 후 클래스를 알맞게 만들려고 힘썼다. 그리고 메서드 분리도 최대한 진행해 보면서 메서드 1개에 하나의 작업만 하도록 만들려고 노력해 봤는데, 1주차에 비해 확실히 더 쉽게 나눌 수 있었다. &lt;/p&gt;
&lt;p&gt;아직 익숙하진 않았지만 확실히 적용하면서, 각 구성 요소가 독립적으로 동작하기 때문에 각 부분을 수정하거나 확장할 때 더 편했고, 가독성이 많이 좋아진다는 걸 느낄 수 있었다.&lt;/p&gt;
&lt;h2&gt;[커밋 메시지를 의미 있게 작성하기]&lt;/h2&gt;
&lt;p&gt;커밋 메시지는 지금까지 헤더만 작성하는 버릇이 있었는데 우테코에서 제공된 커밋 메시지 컨벤션문서를 확인하고 조금 더 의미 있는 커밋메시지를 작성하려고 노력하였다. 기능별로 커밋하면서 어떤 메서드인지 작성하는 노력 하면서 동시에 리팩토링을 진행할 때는 왜 이렇게 바꾸었는지 고민하면서 커밋메시지를 작성하려고 노력하였다. &lt;/p&gt;
&lt;p&gt;아직 익숙하진 않지만 계속 컨벤션을 유지하면 협업이나 누군가 내 코드를 볼 때 확실히 도움 받을 수 있을 거라고 생각한다.&lt;/p&gt;
&lt;h2&gt;[부족하다고 생각하는 점]&lt;/h2&gt;
&lt;p&gt;일단 테스트 코드가 매우 중요하다고 생각하는데, 이번주 미션에선 아직 TDD방법론을 적용해보진 못했다. &lt;/p&gt;
&lt;p&gt;다음 주 미션 때는 적용하기 위해 기능별 테스트코드를 먼저 작성 후 기능에 맞게 동작하는지 확인하면서 코드를 작성해보려고 한다. 그러기 위해서는 확실히 테스트 코드 작성법에 대해서 더 공부해야겠다고 느꼈고, 다음 주는 시간 분배를 조금 더 신경 써서 해야겠다고 생각했다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[우테코] 프리코스 1주차 회고]]></title><description><![CDATA[1주 차 온보딩 github 시작하면서 프리코스…]]></description><link>https://hoonblog.netlify.app/wooteco-free-1/</link><guid isPermaLink="false">https://hoonblog.netlify.app/wooteco-free-1/</guid><pubDate>Wed, 25 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.35294117647059%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAckEgn//xAAXEAEAAwAAAAAAAAAAAAAAAAABABAR/9oACAEBAAEFAjIpX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABcQAAMBAAAAAAAAAAAAAAAAAAAQITH/2gAIAQEABj8Cpi//xAAZEAACAwEAAAAAAAAAAAAAAAARQQABEIH/2gAIAQEAAT8hZQxQe5//2gAMAwEAAgADAAAAEIvf/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8QZ//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAgEBPxARf//EABgQAAMBAQAAAAAAAAAAAAAAAAABEVEx/9oACAEBAAE/EJOhMsGVLdtj6f/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg&apos; srcset=&apos;/static/a99ed4151ee311be6b774d7b6e8431ff/0b705/1.jpg 170w,
/static/a99ed4151ee311be6b774d7b6e8431ff/31389/1.jpg 340w,
/static/a99ed4151ee311be6b774d7b6e8431ff/e224a/1.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/donghoonyeom/java-baseball-6/tree/donghoonyeom&quot;&gt;1주 차 온보딩 github&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;[시작하면서]&lt;/h2&gt;
&lt;p&gt;프리코스 1주 차 온보딩 미션을 진행하면서 느꼈던 부분과 클린 코드 문서를 통해 배웠던 부분을 회고해보려고 한다.&lt;/p&gt;
&lt;h2&gt;[클린 코드]&lt;/h2&gt;
&lt;p&gt;부끄럽지만 난 지금까지 개발을 공부하면서 클린코드를 진행한 적이 없다. 처음 알게 된 건 우테코 디스코드 커뮤니티에서 한 지원자분께서 클린코드에 대한 내용을 올려주셨었는데 &lt;a href=&quot;https://github.com/woowacourse/woowacourse-docs/blob/main/cleancode/pr_checklist.md&quot;&gt;우테코 PR전 체크리스트라는 github문서&lt;/a&gt;였다.&lt;/p&gt;
&lt;p&gt;그 문서에는 PR전에 자신의 코드가 클린코드적용이 되어있는지 체크리스트들이 적혀있었는데, 대부분 내가 개발을 진행하면서 처음 접하는 내용들이었다. 코드 작성 전 가장 먼저 코드컨벤션부터 맞추고 진행하였다. &lt;/p&gt;
&lt;p&gt;난 문서에서 제시하는 Google Java 코드 컨벤션을 적용하였고, 커밋 전 자동으로 컨벤션을 맞춰주는 플러그인을 설치해서 적용하였다. 문서를 읽으며 가장 궁금했던 부분은 else예약어 부분이었다. 항상 if문을 사용하면 무조건 else도 함께 사용해 왔는데 어떻게 사용하지 않고 작성할 수 있지? 궁금증이 생겨 여러 블로그 글이나 GPT에게 질문해 보며 찾아보았다. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;빠른 반환 - number를 조건에 만족하는 즉시 반환되어 중복된 else 문을 사용하지 않을 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;number &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;양수입니다.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;number &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;음수입니다.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0입니다.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; number &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;조건부 표현식 -  &quot;(조건) ? 참일때의 값 : 거짓일때의 값&quot; 형태로 작성되며, 여기서 중첩된 조건을 간결하게 표현할 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;number &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;양수입니다.&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;number &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;음수입니다.&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0입니다.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; number &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;[테스트 코드]&lt;/h2&gt;
&lt;p&gt;개발을 공부해보면서 직접 내가 어떤 예외가 발생할지 고민해 보며, 처음으로 작성해 보았다. 어떤 테스트가 적당할지 고민해 봤지만 예외가 발생할 수 있다고 생각되는 부분에서 테스트하기로 하였다. &lt;/p&gt;
&lt;p&gt;가장 예외가 발생할 것이라고 생각되는 부분은 사용자의 입력이 올바르지 않을 때였다. 사용자가 게임을 시작하면 입력할 수 있는 건 1~9 범위의 서로 다른 3가지 수밖에 없다. 가장 먼저 3가지 이상의 수를 입력했을 때, 1~9 범위를 벗어났을 때, 중복된 숫자가 있을 때, 숫자가 아닌 다른 문자를 입력했을 때 이렇게 4가지 변수를 생각하고 &lt;code class=&quot;language-text&quot;&gt;IllegalArgumentException&lt;/code&gt;를 이용해 예외처리를 해주었다. 마찬가지로 게임 재시작 부분에서 1,2가 아닌 다른 수나,  문자를 입력하는 부분도 같은 방법으로 예외 처리를 진행했고, 우테코 초기 테스트에 추가로 내가 부족하다고 느낀 부분을 추가해서 테스트를 진행했다. &lt;/p&gt;
&lt;p&gt;하지만 테스트 코드를 제대로 작성해 본 적이 없어서 가독성을 생각하지 못해서 given-when-then을 분리해서 작성하지 못했고, 더 많은 테스트케이스를 생각해내지 못했다. 2주 차부터는 이번주보다 부족하다고 생각되는 부분을 보완하려고 한다.&lt;/p&gt;
&lt;h2&gt;[마무리]&lt;/h2&gt;
&lt;p&gt;난 항상 개발을 해올 때 프로그램이 큰 문제없이 돌아가기만 한다면 크게 코드의 재사용성이나 가독성에 대해서 생각해 본 적은 없었다. 하지만 정말 큰 착각이었다. &lt;/p&gt;
&lt;p&gt;이번 주를 진행하면서 전에 생각도 해보지 못한 코드의 가독성이나 코드의 재사용성을 높일 수 있는 클린코드에 대한 부분과 테스트 코드의 중요성을 깨닫게 된 것 같다. 확실히 프리코스 전보다 많이 성장한 게 느껴지지만, 아직 부족하다고 생각되는 부분이 너무나도 많다. &lt;/p&gt;
&lt;p&gt;다음 주 미션부터는 더 좋은 코드를 만들기 위해 클린코드 진행을 조금 더 확실히 해야겠다는 생각과 테스트코드에서의 given-when-then을 분리한다던가 더 많은 테스트 케이스를 작성해 보고 싶다고 생각한다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[해시 테이블(Hash Table)]]></title><description><![CDATA[해시 테이블(Hash Table…]]></description><link>https://hoonblog.netlify.app/hash-table/</link><guid isPermaLink="false">https://hoonblog.netlify.app/hash-table/</guid><pubDate>Wed, 02 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;해시 테이블(Hash Table)이란?&lt;/h2&gt;
&lt;p&gt;데이터를 저장하고 검색하는 데 사용되는 자료구조 중 하나. 특히, 데이터를 효율적으로 검색할 수 있도록 설계되어 있다. 해시 테이블은 &apos;해시 함수&apos;라는 함수를 사용하여 데이터를 배열의 인덱스로 변환하고, 해당 인덱스에 데이터를 저장한다.&lt;/p&gt;
&lt;p&gt;해시 함수는 데이터의 특정 특성을 활용하여 고유한 해시 값(해시 코드 또는 해시 키)을 생성하는 역할을 한다. 이렇게 생성된 해시 값은 배열의 인덱스로 사용되어 데이터가 해시 테이블 내 어느 위치에 저장되어야 할지를 결정한다.&lt;/p&gt;
&lt;p&gt;일반적으로 해시 함수는 입력 데이터와 출력 해시 값의 길이가 다르더라도, 동일한 입력에 대해 항상 동일한 해시 값을 반환해야 한다. 이렇게 해시 함수를 설계함으로써 해시 충돌을 최소화 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/336882d0e92821c5113d2b522cb9eb6f/2876f/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 70.58823529411764%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAACs0lEQVR42o2Ua2/TSBSG+fcsLBIg0C58AAUEEqhFu1sJCqUibS5OTJw4tEnqJI2TtLk6iW8x5ObkYWyX0vbTjvUeHZ858+jYZ2ZucTE2m82lfo3ZbIbruniedy1+M//q3K2rCTf9brdLMpmkWCxem1uv16EC3/f9S/8aUNM00uk0uq6H74PBADVf4KRcQfmqcNZqX0Ln8wWqqlIqlZBSEhWRs1qtfgMDdhCYTqcsFotwwl/71M02NbOFZjY5nw7CuGH2aHd12p0WrU5T+C3Oei06vc71Cm8Of+MjT8ocGHniowJ54wTHtskWNPalDMn6HofaJ+Llj+yX3iNVDiPgTJht0ybWOuN1f8gLvUmsN+RkuUTuqnzpKuy1MqR0hcapzva7Lm/eF3lbfcyLwn1iyn2e5/9kv/FPBAw+MO16fDHGJJypqGbCgePRXi7ICODOSZwtdZekAGpalZ2dDlu7Bd6W/yL29QFvjv/mmXyPveoF0A8a4K/pr3y6iyUdsVU6ojp3s0bqFdltpEiMihxN6vgiJ18Sv0FOk9czKLoklEE+TaFo2QjoCfPUcvijesrdWoPbxxXunPdQ5nOkpszBUBUqcGw1wgWuZzOxx5i2yWgywhgPmVgTTMuMgEGH1xedvqqlaEre1kiNvoUVluwI6M0dxtZQgAz6wz79QS/0jZERAX8IExuOeVSt86TZ5qne5oH4+ao4HZkzhc/ncqgj6zRcoFaqxLNpMrXDSNUDEuV9cpoUAZfC5L7/IDmeIFk2kmmREOqIpsj9Ih+bUqhEI8fR0TH//tdn64PKdu0Jr4qPeak85HnuHnF95//tw8ORStwo8M2sh/FKo0oylyJfz6LURGNqWXI10Zyy/Bu4Ds7nDQWPu/SwF1OshbggVrPowlh+DxtjuzaO6+BMHSzHCv0A+BPtCASJDftk9wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://velog.io/@syoung125/해시테이블이란&apos; title=&apos;&apos; src=&apos;/static/336882d0e92821c5113d2b522cb9eb6f/ca1dc/1.png&apos; srcset=&apos;/static/336882d0e92821c5113d2b522cb9eb6f/e7570/1.png 170w,
/static/336882d0e92821c5113d2b522cb9eb6f/f46e7/1.png 340w,
/static/336882d0e92821c5113d2b522cb9eb6f/ca1dc/1.png 680w,
/static/336882d0e92821c5113d2b522cb9eb6f/2876f/1.png 968w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://velog.io/@syoung125/해시테이블이란&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;해시 테이블의 특징&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;빠른 검색과 삽입 : 해시 함수를 사용하여 데이터를 빠르게 찾고 삽입할 수 있다. 평균적으로 O(1)의 시간 복잡도로 검색과 삽입이 가능&lt;/li&gt;
&lt;li&gt;해시 충돌 : 서로 다른 데이터가 같은 해시 값으로 매핑될 수 있는데, 이를 해시 충돌이라고 한다. 충돌이 발생하는 경우에 대처할 수 있는 방법들이 있는데, 가장 일반적인 방법은 해시 테이블의 각 버킷에 연결 리스트를 사용하여 충돌이 발생한 데이터를 연결하는 것이다.&lt;/li&gt;
&lt;li&gt;공간 효율성 : 해시 테이블은 적은 메모리 공간으로 많은 데이터를 효율적으로 관리할 수 있다.&lt;/li&gt;
&lt;li&gt;해시 함수의 선택 : 해시 함수의 선택은 해시 테이블의 성능에 큰 영향을 준다. 좋은 해시 함수는 데이터를 가능한 한 균일하게 해시 테이블에 분배하여 충돌을 최소화해야 한다.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[맵 (Map)]]></title><description><![CDATA[맵(Map)이란? 맵은 특정 순서에 따라 키와 매핑된 값의 조합으로 형성된 자료구조이다. 맵은 키-값 쌍의 집합으로, 특정 키를 통해 연결된 값을 검색하고 저장하는 데 사용된다.  맵의 특징 유일한 키(Key…]]></description><link>https://hoonblog.netlify.app/map/</link><guid isPermaLink="false">https://hoonblog.netlify.app/map/</guid><pubDate>Tue, 01 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;맵(Map)이란?&lt;/h2&gt;
&lt;p&gt;맵은 특정 순서에 따라 키와 매핑된 값의 조합으로 형성된 자료구조이다. 맵은 키-값 쌍의 집합으로, 특정 키를 통해 연결된 값을 검색하고 저장하는 데 사용된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/731c178b7ad166f81a7bcd76678359b1/5b101/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 59.411764705882355%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAACOklEQVR42o2SS09TURSF+0ucOXPi0ImO/AeOpRhrmKgDAuVRqiTGQGgiNDyLPEyM1kExMSGlQhHsg9pbKAK2BMqjJEALBIGSXi69t5/nIr1gTAg7OcnJycra39l7mTKZLD6vl3G/n6NcDr2KxSLXKU2VkXOb5I+2Oc3voCoHmOJzvzBbnvOs0sbmVuavULswdL37RPVLB68cXVTbW3APeY2mmqZycLBHNrslYA6R5TympdUNmp19OF3v2dndPxOrqkoJ8mGFlZu373Ln/gNu3LpHTaPjvKmKclpge2efjc0Mvw+P0TlMV37pNMf+7hp72RVi8wmW0lnS23soBfUfnU5bGpOpdCkUCszPLxCTYkiRCULfvrC+ushKaomfs3NEozPEZ2ZYXUszPbvAsG+c8FQUSZJYXk4ZxoZhPp/HXlfP04oK6qqqsJgf4fF8xtnaxhNzObXVVh6XlTHQP0B3RyeWMjPWSl1XLjTOC8MSdkHMLS5IgoEJwgE/oWCY9fU0iURSvIWYnBwmEAiwnFohmVwUb0GkaJRwMEQysfg/oaIouD+6cXV1MPjWRWd7O5HID0a8I/R299Df10VvTw9+Ea+romUYyvIJbW9aaWyw42huwWatwecbZbB/EFttHU2vm2gQI3F/cBtJ0DTNOIZh6aILUuI7sek4oYjEgliQHnpNNDwR9Mr50XVX1aWlyLyot50tpV7QWcxmhjye88xpXLdMpVHosZkKTzE+5icw+Z2xr6OkLsXhuoZ/AAdbT5uzUm9rAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://blog.naver.com/kkkths/221755894067&apos; title=&apos;&apos; src=&apos;/static/731c178b7ad166f81a7bcd76678359b1/ca1dc/1.png&apos; srcset=&apos;/static/731c178b7ad166f81a7bcd76678359b1/e7570/1.png 170w,
/static/731c178b7ad166f81a7bcd76678359b1/f46e7/1.png 340w,
/static/731c178b7ad166f81a7bcd76678359b1/ca1dc/1.png 680w,
/static/731c178b7ad166f81a7bcd76678359b1/5b101/1.png 773w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://blog.naver.com/kkkths/221755894067&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h2&gt;맵의 특징&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;유일한 키(Key) : 하나의 키는 맵 내에서 유일해야 합니다. 중복된 키를 허용하지 않는다.&lt;/li&gt;
&lt;li&gt;효율적인 검색 : 키를 사용하여 값을 검색하는 과정이 빠르고 효율적이어야 한다. 맵은 일반적으로 해시 테이블(hash table) 등을 이용하여 빠른 검색을 지원&lt;/li&gt;
&lt;li&gt;동적 크기 조정 : 맵은 동적으로 크기를 조정하여 새로운 key-value 쌍을 추가하거나 기존 키-값 쌍을 삭제할 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;순서 보장 여부 : 일부 맵 구현은 삽입된 순서를 보장하여 데이터를 저장하지만, 다른 구현은 순서를 보장하지 않을 수 있다. 언어 또는 라이브러리에 따라 다를 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;맵 자료구조는 다양한 프로그래밍 시나리오에서 사용된다. 예를 들어, 데이터베이스 결과를 처리하거나, 카운팅 및 집계 작업, 키워드 검색, 캐시 관리 등에 유용하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;자바에서 맵 구현&lt;/h2&gt;
&lt;p&gt;자바에서의 맵 사용 예를 들어보려고 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;HashMap&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Map&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ExampleHashMap&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// HashMap 생성과 값 추가&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; myMap &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;apple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;banana&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;orange&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 값 접근&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; appleValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;apple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Apple: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; appleValue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 출력: Apple: 1&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 값 수정&lt;/span&gt;
        myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;banana&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 새로운 값 추가&lt;/span&gt;
        myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;grape&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 특정 키가 맵에 있는지 확인&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;containsKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;orange&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Orange exists!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 키-값 쌍 순회&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Map&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Entry&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; entry &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entrySet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; key &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 키 목록 가져오기&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// (Java 8 이상에서는 keySet() 메서드를 사용하면 더 간단하게 처리 가능)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; key &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keySet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Key: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 값 목록 가져오기&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Value: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 특정 키 삭제&lt;/span&gt;
        myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;apple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 예시에서 &lt;code class=&quot;language-text&quot;&gt;HashMap&lt;/code&gt;을 이용하여 맵을 생성하고, &lt;code class=&quot;language-text&quot;&gt;put&lt;/code&gt; 메서드를 사용하여 키-값 쌍을 추가하고 수정, &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt; 메서드를 사용하여 특정 키에 대응하는 값을 가져온다. &lt;code class=&quot;language-text&quot;&gt;containsKey&lt;/code&gt; 메서드로 특정 키가 맵에 있는지 확인, &lt;code class=&quot;language-text&quot;&gt;entrySet&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;keySet&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;values&lt;/code&gt; 메서드를 통해 맵의 키-값 쌍, 키 목록, 값 목록을 순회할 수 있다. 마지막엔 &lt;code class=&quot;language-text&quot;&gt;remove&lt;/code&gt; 메서드를 사용하여 특정 키를 삭제하는 것을 확인할 수 있다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[우선순위 큐 (Priority Queue)]]></title><description><![CDATA[…]]></description><link>https://hoonblog.netlify.app/priority-queue/</link><guid isPermaLink="false">https://hoonblog.netlify.app/priority-queue/</guid><pubDate>Tue, 01 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;우선순위 큐란?&lt;/h2&gt;
&lt;p&gt;각 요소들이 각각의 우선 순위를 갖고있고, 요소들의 대기열에서 &apos;우선 순위가 높은 요소&apos;가 &apos;우선 순위가 낮은 요소&apos;보다 먼저 제공되는 자료구조다. 힙을 기반으로 구현되나 힙과는 다른 개념이다.&lt;/p&gt;
&lt;p&gt;힙은 기본적으로 중점이 되는 것이 &apos;최솟값 또는 최댓값 빠르게 찾기&apos;인 반면, 우선순위 큐는 우선순위가 높은 순서대로 요소를 제공받는다.&lt;/p&gt;
&lt;p&gt;기본적으로 큐와 유사한 형태를 가지고 있으며, 다만 큐는 데이터가 들어온 순서대로 처리되지만, 우선순위 큐는 우선순위가 높은 데이터가 먼저 처리됩니다. 우선순위 큐는 최댓값이나 최솟값을 빠르게 찾아내는데 유용하게 사용됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/365819fa4e500491a40140e6e26bf26c/b9f8c/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 81.76470588235294%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAABd0lEQVR42q1TWU+DYBDk//8RH43xRROffFSTHhR6QSmUw1rKZVuOtoy7X4qhilqrm2wIm28ns7M7Eg5RlmVjovoe3mzWa6xWK6Rp+l6vh4QTghuL3Q4Lf4EwDAXo0vfx7LnY7/cijwC3RYGIHkZRhCRJEAaBaOBalmVYOA6Cu3ssr2+xVobId1sYug5josO2LNF/BFhQ4WU+h8eNSx/aaITRYADTMMRo3tREcHWD4OIS8UNLNO6JcZ1Z48iVJszOp/EiYsqREWi/04H8+ISZMT08bpZHalpK/Z8jTTfoqypkWYZj29/qLX21hDog66jIXXRbLcxIs18DfgweWe310Gm3YZ/D8BOgYChDJh0t0zzS+yxA3rQ2HmM0HMKlS/gXhqqiiLGtabXl8m8aMrsB3abnuv/BkO5QJYaUlYYnA7LYGd0du6fIc+SUa/IuM9Q07YyzIWk818FE1zAmkFfyNluMvTuhjMnvZ43MTBksiWORbEfe9k/xBn5b3uE4J5joAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;면접을 위한 CS 전공지식 노트&apos; title=&apos;&apos; src=&apos;/static/365819fa4e500491a40140e6e26bf26c/ca1dc/1.png&apos; srcset=&apos;/static/365819fa4e500491a40140e6e26bf26c/e7570/1.png 170w,
/static/365819fa4e500491a40140e6e26bf26c/f46e7/1.png 340w,
/static/365819fa4e500491a40140e6e26bf26c/ca1dc/1.png 680w,
/static/365819fa4e500491a40140e6e26bf26c/b9f8c/1.png 854w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;면접을 위한 CS 전공지식 노트&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;우선순위 큐의 연산&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;삽입(Insertion): 요소를 우선순위에 맞게 삽입&lt;/li&gt;
&lt;li&gt;삭제(Deletion): 우선순위가 가장 높은(또는 낮은) 요소를 삭제&lt;/li&gt;
&lt;li&gt;최댓값 또는 최솟값 확인(Peek): 우선순위가 가장 높은(또는 낮은) 요소를 반환하지만 삭제하지는 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;우선순위 큐 알고리즘은 삽입과 삭제 연산 시에 이진 힙의 성질을 유지하는 것이 중요하다. 이진 힙의 성질을 유지하지 않으면 올바른 우선순위 큐로 동작하지 않을 가능성이 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;우선순위 큐의 활용&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;작업 스케줄링(Job Scheduling): 우선순위가 높은 작업을 먼저 처리하기 위해 사용&lt;/li&gt;
&lt;li&gt;힙 정렬(Heap Sort): 우선순위 큐를 활용하여 정렬을 수행하는 정렬 알고리즘&lt;/li&gt;
&lt;li&gt;Huffman 코딩: 데이터 압축 알고리즘에서 사용되는 특별한 형태의 우선순위 큐&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[큐 (Queue)]]></title><description><![CDATA[들어가며 큐(Queue)는 데이터를 임시로 저장하고 처리하는 자료구조 중 하나입니다. 이는 데이터를 선입선출(First-In-First-Out, FIFO)의 순서로 다루는 구조이며, 스택과는 반대되는 개념을 가지고 있다. 삽입 및 삭제에 O(…]]></description><link>https://hoonblog.netlify.app/queue/</link><guid isPermaLink="false">https://hoonblog.netlify.app/queue/</guid><pubDate>Tue, 01 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;들어가며&lt;/h2&gt;
&lt;p&gt;큐(Queue)는 데이터를 임시로 저장하고 처리하는 자료구조 중 하나입니다. 이는 데이터를 선입선출(First-In-First-Out, FIFO)의 순서로 다루는 구조이며, 스택과는 반대되는 개념을 가지고 있다. 삽입 및 삭제에 O(1) , 탐색에 O(n)이 걸린다.&lt;/p&gt;
&lt;p&gt;큐는 일상 생활에서 줄 서기와 유사한 개념으로 이해할 수 있습니다. 가장 먼저 온 사람이 먼저 서비스를 받는 것과 같이, 큐에 추가된 데이터도 가장 먼저 처리되어 나옵니다. CPU작업을 기다리는 프로세스, 스레드 행렬, 네트워크 접속을 기다리는 행렬, 너비 우선 탐색, 캐시도 같은 개념이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/50c593ee8ee6a881ebf49f35ae3362ea/b9f8c/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 117.05882352941177%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAYAAAALHW+jAAAACXBIWXMAABYlAAAWJQFJUiTwAAACe0lEQVR42p1Ua2/aQBDM//8xVb9UlVpVqOkHIKFBAWJjHn6Abc42NjbGGPya7p2hogkE0pNWhrNvbndmdu9wZhVFgbIsUVXVmyjyXHyT+3Ok8RKLyESwTeEl9f7dKRA/wFcURdA0DbPZ7E1Mp1O4Sx/z7j18pkJbTsDiGPNodxlws9lgPp/DsixYti3CNE0sFgsoigJd16GMx/D94J9zFwHX6zWGsoyInpsgwNpxsdvvRdYcjK/ySAvqM9U5wHPgpc2QyyNx4DW359bZDIOlh9FzC72XB/yWh1SeBotKNgwDNpX/3jrPYRhAuv+Mn81P+N4fQDYYfM+FQ6UHQfBxwDAMIUkS/NUKUbjCyvcFr3yPZ/laiIuAp8B5ltUcOh6KaQ3CPcg5vDnDo1ZpmtaHCThbx8iWAXIShIuSJMnHSpbILr1eH9JQwo/mV3xptdCRJtA1FWPynuM41wH/dggzILUbwsCyMkRXekCbLlB0E7ZlQlVVYfbrGR4As5AhZVNk+0x0Ss75Sncoo1i8twnM87z/EwUnxi7Ih8eLLwFdBPTJItwaPEOX+JoYVCoF546Xy+m4GTDdbtBsNzEYDESokzG+tbpodHoYjxQMaTBcF+VQQhH7cPoN9LRH2EuLVNVp6sTYZTlSGgxZVvPKB8RNGVZFjjyhzkhX2Od7YWx+VbUKicc6K77HvXgDYHUygCCy4QZOdjtExgyhrGBDZk9oTn7Y2DqVpKpTMVQdxsBcF4yswvhvCpf+XwUsU+IqcrAITPx6fMJT7wUjEoEryr0ngi44TvGrgFmwAFNaeJ51YIRbeHGKma4hphL3JAjv7aMot3fKwbTlDeZ9D/APRJLzXeUBJgYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://st-lab.tistory.com/183&apos; title=&apos;&apos; src=&apos;/static/50c593ee8ee6a881ebf49f35ae3362ea/ca1dc/1.png&apos; srcset=&apos;/static/50c593ee8ee6a881ebf49f35ae3362ea/e7570/1.png 170w,
/static/50c593ee8ee6a881ebf49f35ae3362ea/f46e7/1.png 340w,
/static/50c593ee8ee6a881ebf49f35ae3362ea/ca1dc/1.png 680w,
/static/50c593ee8ee6a881ebf49f35ae3362ea/b9f8c/1.png 854w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://st-lab.tistory.com/183&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[트랜잭션과 무결성]]></title><description><![CDATA[들어가며 트랜잭션(Transaction)은 데이터베이스에서 하나의 논리적 기능을 수행하기 위한 작업의 단위를 말하며, 데이터베이스에 접근하는 방법은 쿼리이므로, 즉 여러 개의 쿼리들을 하나로 묶는 단위를 말한다. 트랜잭션은 원자성(Atomicity…]]></description><link>https://hoonblog.netlify.app/transactions-integrity/</link><guid isPermaLink="false">https://hoonblog.netlify.app/transactions-integrity/</guid><pubDate>Mon, 24 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;들어가며&lt;/h2&gt;
&lt;p&gt;트랜잭션(Transaction)은 데이터베이스에서 하나의 논리적 기능을 수행하기 위한 작업의 단위를 말하며, 데이터베이스에 접근하는 방법은 쿼리이므로, 즉 여러 개의 쿼리들을 하나로 묶는 단위를 말한다. 트랜잭션은 &lt;strong&gt;&lt;em&gt;원자성(Atomicity)&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;일관성(Consistency)&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;격리성(Isolation)&lt;/em&gt;&lt;/strong&gt;, 그리고 &lt;strong&gt;&lt;em&gt;지속성(Durability)&lt;/em&gt;&lt;/strong&gt; 이라는 특성을 갖는다. 이 네 가지 특성은 트랜잭션의 안전성과 무결성을 보장하는데 중요한 역할을 한다.&lt;/p&gt;
&lt;h3&gt;트랜잭션의 흐름&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;트랜잭션 시작 (BEGIN 또는 START TRANSACTION 명령)&lt;/li&gt;
&lt;li&gt;데이터베이스 작업 수행 (SELECT, INSERT, UPDATE, DELETE 등)&lt;/li&gt;
&lt;li&gt;모든 작업이 성공적으로 수행되면 커밋 (COMMIT 명령으로 트랜잭션 완료)&lt;/li&gt;
&lt;li&gt;오류 또는 중단이 발생하면 롤백 (ROLLBACK 명령으로 트랜잭션 취소)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;원자성(Atomicity)&lt;/h2&gt;
&lt;p&gt;트랜잭션은 &lt;strong&gt;&lt;em&gt;작업의 모든 단계가 완벽하게 수행되거나 전혀 수행되지 않아야 한다.&lt;/em&gt;&lt;/strong&gt; 예를 들어 트랜잭션을 커밋했는데, 문제가 발생하여 롤백하는 경우 그 이후에 모두 수행되지 않음을 보장하는 것을 말한다. 하나의 원자적인 단위로 묶여있기 때문에 중간 단계의 실패로 인해 데이터베이스가 비일관성 상태에 빠지는 것을 방지한다.&lt;/p&gt;
&lt;h3&gt;커밋과 롤백(Commit, Roll back)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;커밋은 트랜잭션이 성공적으로 완료되어 데이터베이스에 수행한 모든 작업들이 영구적으로 저장되도록 하는 명령이다.&lt;/em&gt;&lt;/strong&gt; 즉, 커밋 명령을 실행하면 트랜잭션 내의 모든 데이터베이스 작업들이 데이터베이스에 반영되고, 이후에는 해당 트랜잭션에서 수행한 변경 사항이 영구적으로 유지된다. 커밋 이후에는 데이터베이스는 일관성을 유지하며, 다른 트랜잭션들도 해당 변경 사항을 볼 수 있게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/376f2e05dc458bc6205ddf57e7bddd5c/1e677/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 44.705882352941174%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABYklEQVR42q1S207CQBDlt/0A4x/44quRkPiCJj7wBJGEm2AMSVHBbWmXCu229kah1+NuAQXxkUkmO2dmMnvOzpbALc/zwk9hpV0QxzEcz4dihRhRC+OFhyjNIbMlRjMbxAywSjIoLOB1u8gn2TGJUhiGmKoqbItBmzN0Jh4a3Q88SjbMMENf9tF+0fFEfFA3wYC4aA0U9Dl21zmyLIblW1iul5uBaZrC9314ngfTMDFc9NCQ71EbV+CtbAznPdSVX9ynLdQmVTy83nAFIQzXQLl5hWfSPZTMX5LflqM5LePu/QLl4Rk+HRlt9RbVt/MtVtBSK7y+wc7KgM3ZXdcvOfPO34Gb5WRZVsSC+b6l2/w+Fr1xEoMFBpccHA4URcf5ApEJ6IyCMQaTmUUsixzVYJoGjK3LigyVv73Ywb9bjqKoaNB1HZZl/XwlSikkSYKmacWlgrlwgQkhxblTdyT5FP/wG7vyqoFmTA4HAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;커밋&apos; title=&apos;&apos; src=&apos;/static/376f2e05dc458bc6205ddf57e7bddd5c/ca1dc/1.png&apos; srcset=&apos;/static/376f2e05dc458bc6205ddf57e7bddd5c/e7570/1.png 170w,
/static/376f2e05dc458bc6205ddf57e7bddd5c/f46e7/1.png 340w,
/static/376f2e05dc458bc6205ddf57e7bddd5c/ca1dc/1.png 680w,
/static/376f2e05dc458bc6205ddf57e7bddd5c/02d09/1.png 1020w,
/static/376f2e05dc458bc6205ddf57e7bddd5c/1e677/1.png 1220w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;커밋&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;위 그림처럼 update,insert,delete의 쿼리가 하나의 트랜잭션 단위로 수행되고 이후에 데이터 베이스에 영구 저장된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;롤백은 트랜잭션을 취소하고 트랜잭션 이전의 상태로 되돌리는 명령이다.&lt;/em&gt;&lt;/strong&gt; 즉, 트랜잭션 내에서 오류가 발생하거나 트랜잭션을 중단해야 하는 경우 롤백 명령을 실행하여 이전 상태로 데이터베이스를 되돌린다. 롤백을 실행하면 트랜잭션에서 수행한 모든 변경 사항들이 취소되고, 데이터베이스는 트랜잭션 이전의 상태로 돌아간다. 이후에는 해당 트랜잭션에서 수행한 작업들이 데이터베이스에 영향을 미치지 않은 것처럼 보인다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/127b750139923b3ddb590f0b28433272/1e677/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 54.70588235294118%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB4UlEQVR42m1TXW/TQBD0r694RkU8FyFViIcCEgIqVNRKCCK1UOO2xGlM7NgmcXz2xXHir7NvWJ8xbUhXOlm7sze7O3vW8J9JCTR/T+93Mam+D5lUWAdqfbCsKqSrBBbLoNtz6FMGngk4UYZrj0F3Y8TkT+MMhhMQHiHaiI7wHrkmhIBt2/B8HzwKMQwqfBo4OPk+R5AKWIsSg6sFzoxQ+cN5jtMLH8ff5vCTSpH4kQePTSFqAa1ttSXdbNZY8RQ3iwFemfs4vNrDiA1wG+o4Mh/j0NjDz8VnmsDA69E+Xlw/wo/ZiSJ8e/4SR1+fIy/zu5F7DSbxJc6cZ3g/foIJ1+EtTfIP8IF8K76Avxwp/Nh6CpN9IXGB05t3+Gi8IcLijrC3irRsyZuaOi+FGkMVpIuiqtU0rWgNbS3Pik5/UaKoiu2lNE0Dzjksa4zRrQkWMURRhNnsN0xzCOvXGGG4AGOMsBC2M4FhGAiCoCvSL6V9C7JIqYOGLoTqQpIk/xLSNKUiFlzXVd33lmU5Zr4Lb+psxTVZ5ZDruFfywbeFe2gfkTSm3PCdN6nRrGjSCDJfdUltgabeIWljCqdNSspv1hyyrneKav3vIElUmVFSllDlJXXNt08ba/E8bQXfmagn/APOjUboYccEEgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;롤백&apos; title=&apos;&apos; src=&apos;/static/127b750139923b3ddb590f0b28433272/ca1dc/2.png&apos; srcset=&apos;/static/127b750139923b3ddb590f0b28433272/e7570/2.png 170w,
/static/127b750139923b3ddb590f0b28433272/f46e7/2.png 340w,
/static/127b750139923b3ddb590f0b28433272/ca1dc/2.png 680w,
/static/127b750139923b3ddb590f0b28433272/02d09/2.png 1020w,
/static/127b750139923b3ddb590f0b28433272/1e677/2.png 1220w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;롤백&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;이러한 커밋과 롤백으로 데이터의 무결성이 보장되고, 데이터 변경 전에 변경사항을 쉽게 확인할 수 있고 해당 작업을 그룹화할 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;트랜잭션 전파&lt;/h3&gt;
&lt;p&gt;트랜젝션을 수행할 때 커넥션 단위로 수행하기 때문에 커넥션 객체를 넘겨서 수행해야 한다. 하지만 이를 매번 넘겨주기가 어렵기도 하고 귀찮기도 하다. 이를 넘겨서 수행하지 않고 여러 트랜잭션 관련 메서드의 호출을 하나의 트랜잭션에 묶이도록 하는 것을 트랜잭션 전파라고 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Service&lt;/span&gt; 
&lt;span class=&quot;token annotation punctuation&quot;&gt;@Transactional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;readOnly &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MemberService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MemberRepository&lt;/span&gt; memberRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MemberService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MemberRepository&lt;/span&gt; memberRepository&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;memberRepository &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; memberRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;위 코드처럼 &lt;code class=&quot;language-text&quot;&gt;@Transactional&lt;/code&gt; 애너테이션을 통해 여러 쿼리 관련 코드들을 하나의 트랜잭션으로 처리한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;일관성(Consistency)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;트랜잭션의 시작 전과 끝난 후에도 데이터베이스는 일관된 상태를 유지해야 한다.&lt;/em&gt;&lt;/strong&gt; 즉, 트랜잭션이 실행되기 전과 후에 정의된 규칙과 제약 조건, 허용된 방식을 만족해야 한다. 트랜잭션이 성공적으로 완료된 경우 데이터베이스의 상태가 항상 일관성을 유지해야 한다.&lt;/p&gt;
&lt;h2&gt;격리성(Isolation)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;여러 개의 트랜잭션이 동시에 실행될 때, 각 트랜잭션은 다른 트랜잭션들로부터 독립적으로 수행되는 것처럼 보이도록 격리되어야 한다.&lt;/em&gt;&lt;/strong&gt; 즉, 하나의 트랜잭션이 다른 트랜잭션의 영향을 받지 않고, 서로 간섭하지 않도록 보장해야 한다. 이를 통해 트랜잭션들이 동시에 실행될 때 발생할 수 있는 문제들을 방지하고 데이터 일관성을 보장한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/00ef3f0c88ca2552a29b28e9160b79d3/1e677/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.70588235294117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAABlElEQVR42q1U226CQBDt5zfpey8f1Ie+10ZARazVCgIit0Uup3vGLCXxEh8kmczOMnt2zpmBB9z5ecjzHO5shjhOUFc7ZP4H2rZF13ViXKdpirIswVyuTWxyaD1gVVXY7WKUVQuVegg+H9E0dZ9Q1zUmkwnW6zVc14Vt25jpAhifrfDojjc0pY/IfkVRlIiiSFcd68t01VmG/X4vaxorZWzeh2GIw+FwBlD5iK1nTUdJAqujkQVjeprZb5pGJCH9i4CRBqyqI2UmOo4j9MbjMabTKVar1QlNc8EJYK0px/aLFj0XGjTf9xEEATzPE889UqUkBuQi4JAy6Qy7aDpuJkApJfRvqrAolHTWsizp6Hw+lw7zEspAM1reTJm6bTYbAeN6u90K7dFoJPFVwK5r/wE1ZVZohtV4AnBceJB7Q5DLFVJD500fLKUSUqZPkkRAzGgYEF5i9ntA6rFcfiPLNYX8B+HXkwBwPEhtsVgIbQ43NTQPm8M9ykLPWACJzoPUrVYx0t/3/tMbdnf4vV79Odz7b/MHTPKK82+Ou/AAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;격리수준&apos; title=&apos;&apos; src=&apos;/static/00ef3f0c88ca2552a29b28e9160b79d3/ca1dc/3.png&apos; srcset=&apos;/static/00ef3f0c88ca2552a29b28e9160b79d3/e7570/3.png 170w,
/static/00ef3f0c88ca2552a29b28e9160b79d3/f46e7/3.png 340w,
/static/00ef3f0c88ca2552a29b28e9160b79d3/ca1dc/3.png 680w,
/static/00ef3f0c88ca2552a29b28e9160b79d3/02d09/3.png 1020w,
/static/00ef3f0c88ca2552a29b28e9160b79d3/1e677/3.png 1220w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;격리수준&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;격리 수준은 SERIALIABLE, REPEATABLE&lt;em&gt;READ, READ&lt;/em&gt;COMMITTED, READ_UNCOMMITTED가 있다.
위로 갈수록 동시성은 강해지고, 격리성은 낮아 지고, 아래로 갈수록 격리성은 강해지고, 동시성은 낮아진다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;팬텀 리드(Phantom Read): &lt;strong&gt;&lt;em&gt;하나의 트랜잭션 내에서 같은 쿼리를 두 번 이상 실행했을 때, 첫 번째 쿼리에 없던 새로운 행이나 레코드가 두 번째 쿼리에서 나타나는 현상을 말합니다.&lt;/em&gt;&lt;/strong&gt; 이는 다른 트랜잭션에 의해 삽입되거나 삭제된 데이터 때문에 발생할 수 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;예를 들어 사용자 A가 회원 테이블에서 age가 13 이상인 회원들을 조회하는 쿼리를 보냈다는 가정했을 때 결과로 3개의 테이블  을 조회한다고 해보면 그다음 사용자 B가 age가 15인 회원 레코드를 삽입한다. 그러면 3개가 아닌 4개가 조회된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;반복 가능하지 않은 조회(Non-repeatable Read): &lt;strong&gt;&lt;em&gt;하나의 트랜잭션 내에서 같은 쿼리를 두 번 이상 실행했을 때, 첫 번째 쿼리에서 조회한 데이터와 두 번째 쿼리에서 조회한 데이터가 다른 현상을 말합니다.&lt;/em&gt;&lt;/strong&gt; 이는 다른 트랜잭션에 의해 데이터가 변경되거나 삭제되었을 때 발생할 수 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;예를 들어 사용자 A가 조회 했을 때 특정 레코드를 조회하고, 그 후에 사용자 B가 동일한 레코드를 수정하거나 삭제하면, 트랜잭션 A는 같은 쿼리를 다시 실행했을 때 이전과 다른 결과를 얻을 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;더티 리드(Dirty Read): &lt;strong&gt;&lt;em&gt;하나의 트랜잭션에서 아직 커밋되지 않은 다른 트랜잭션의 변경 사항을 읽는 것을 말합니다.&lt;/em&gt;&lt;/strong&gt; 즉, 다른 트랜잭션이 아직 롤백되거나 커밋되지 않았으므로 데이터베이스에 영구적으로 적용되지 않은 값을 읽게 됩니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;예를 들어 사용자 A가 큰돌의 보석개수 100을 1로 변경한 내용이 커밋되지 않은 상태라도 그 이후 사용자 B가 조회한 결과가 1로 나오는 경우를 말한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;SERIALIZABLE (직렬화)&lt;/h3&gt;
&lt;p&gt;가장 높은 격리 수준으로, 트랜잭션이 순차적으로 실행되는 것처럼 보장된다.
다른 트랜잭션에서 데이터를 수정하거나 추가하는 것을 완전히 차단하여 펜텀 리드(Phantom Read)와 반복 가능하지 않은 조회(Non-repeatable Read)를 방지한다. 다른 격리 수준에 비해 더 많은 락(Lock)을 사용하므로 동시성이 떨어질 수 있습니다.&lt;/p&gt;
&lt;h3&gt;REPEATABLE READ (반복 가능한 읽기)&lt;/h3&gt;
&lt;p&gt;트랜잭션 내에서 동일한 쿼리를 여러 번 실행해도 항상 동일한 결과를 얻을 수 있다.
반복 가능하지 않은 조회(Non-repeatable Read)는 발생하지 않지만, 펜텀 리드(Phantom Read)가 발생할 수 있다.
REPEATABLE READ 격리 수준에서는 트랜잭션이 커밋되기 전까지 다른 트랜잭션에서 해당 데이터를 수정하거나 추가할 수 없도록 락(Lock)을 사용한다.&lt;/p&gt;
&lt;h3&gt;READ COMMITTED (읽기 커밋)&lt;/h3&gt;
&lt;p&gt;다른 트랜잭션에서 커밋한 변경 사항만 읽을 수 있다.
더티 리드는 발생하지 않지만, 반복 가능하지 않은 조회(Non-repeatable Read)와 펜텀 리드(Phantom Read)가 발생할 수 있다.
일반적으로 가장 기본적으로 사용되는 격리 수준이며, 많은 데이터베이스 시스템에서 기본으로 설정된다.&lt;/p&gt;
&lt;h3&gt;READ UNCOMMITTED (미허용 읽기)&lt;/h3&gt;
&lt;p&gt;가장 낮은 격리 수준으로, 다른 트랜잭션에서 아직 커밋되지 않은 변경 사항도 읽을 수 있다. 더티 리드(Dirty Read)가 발생할 수 있으며, 다른 트랜잭션에서 롤백되거나 커밋되지 않은 값을 읽을 수 있다. 데이터 일관성과 무결성이 보장되지 않기 때문에 일반적으로 권장되지 않는 격리 수준입니다.&lt;/p&gt;
&lt;h2&gt;지속성(Durability)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;트랜잭션이 성공적으로 완료되면, 그 결과는 영구적으로 유지되어야 한다.&lt;/em&gt;&lt;/strong&gt; 시스템 장애나 손상된 상태에서도 데이터베이스는 지속적으로 트랜잭션의 결과를 보존해야 한다. 데이터 베이스는 이를 위해 체크섬, 저널링, 롤백 등의 기능을 제공한다.&lt;/p&gt;
&lt;h2&gt;무결성(Integrity)&lt;/h2&gt;
&lt;p&gt;데이터의 정확성, 일관성, 유효성을 유지하는 것을 말하며, 무결성이 유지되어야 데이터 베이스에 저장된 데이터 값과 그 값에 해당하는 현실 세계의 실제 값이 일치하는지에 대한 신뢰가 생긴다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;center&quot;&gt;이름&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;개체 무결성&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;기본키로 선택된 필드는 빈 값을 허용하지 않는다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;참조 무결성&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;서로 참조 관계에 있는 두 테이블의 데이터는 항상 일관된 값을 유지해야 한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;고유 무결성&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;특정 속성에 대해 고유한 값을 가지도록 조건이 주어진 경우 그 속성 값은 모두 고유한 값을 가진다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;NULL 무결성&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;특정 속성 값에 NULL이 올 수 없다는 조건이 주어진 경우 그 속성 값은 NULL이 될 수 없다는 제약 조건이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content:encoded></item><item><title><![CDATA[Database 정규화 과정]]></title><description><![CDATA[…]]></description><link>https://hoonblog.netlify.app/database-normalization-process/</link><guid isPermaLink="false">https://hoonblog.netlify.app/database-normalization-process/</guid><pubDate>Sun, 23 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2f93a9cac76d95cfdd869a6421d31699/161f7/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAACQUlEQVR42t2Uz0sUYRzGTahDlFaiUpjprju7O/POvLPtarIKVuu6Lv5aUXRtLW21UhNUNKxMKcswOpWJdAkhEDxU0LlrdOvov/Pp3XEp05UUOnl4+A7zPvOZ533eYfIsy+J/Ku9oAU0lYW7PQwN3PmhmJZVCAQtb7g/dA8yYNZ/kyV0vX5ddbDyuYnPWw+dpD6tpL5OtOsONxuESCmEx2OXn+aiXpds+Fvp8zPf5SccN4mGT1DWDy3bulPtuuSViMNChc0cluqUSJZWidQKpdtASFgQzQPMgQGk7sz0mGEv6mej2M96mk2426IpsJ2uttwgGJMKy/wE0BQGvG9NQiWIuxns0RrsF4wmD4bhOf7NJrNYgdeUSId2D7atCmsY+QAUTwWqKJ99xcu4L5VMr1EcbiNjlhKNXqW1tp8m6SFNDEO/kKwqm1ym+uYgRqstC5Q6glEjdh9bYzonVnxx//YP8uW+UJOepiHRTNLRM4chbymMpSntnOPZ+i7yVLfKffcfdmMTWNcxsVb+BtgNMcO7hOiXpF5wdXaOi7R4iVIMW6UC7nkBUh3G1D1I0+0F5ljgzsoY70usArb1AL1q0k4Knnygae8OpqQ0qYwOqUxfS0JX8BDQXVfFeChc2KRl6yemJj7ijN7D9nl0JnQ5Np8PKziEu9D+iLHEfvTrbj3phJoEUAqOmjrLUDKWDi5zveaA89Tk63HEwtt+rDMKpQIo/xm1J556t0mauM3O3J8d3KP+eueSsmVmQPMr/w4MAfwF2lIoiyvFDMAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Image via Shutterstock under license to Frank Andrade&apos; title=&apos;&apos; src=&apos;/static/2f93a9cac76d95cfdd869a6421d31699/ca1dc/1.png&apos; srcset=&apos;/static/2f93a9cac76d95cfdd869a6421d31699/e7570/1.png 170w,
/static/2f93a9cac76d95cfdd869a6421d31699/f46e7/1.png 340w,
/static/2f93a9cac76d95cfdd869a6421d31699/ca1dc/1.png 680w,
/static/2f93a9cac76d95cfdd869a6421d31699/02d09/1.png 1020w,
/static/2f93a9cac76d95cfdd869a6421d31699/161f7/1.png 1250w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;Image via Shutterstock under license to Frank Andrade&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h2&gt;들어가며&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;정규화 과정은 릴레이션 간의 잘못된 종속 관계로 인해 데이터베이스 이상 현상이 일어나 이를 해결하거나, 저장공간을 효율적으로 사용하기 위해 릴레이션을 여러 개로 분리하는 과정을 말한다.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;여기서 말하는 데이터베이스 이상 현상은 예를 들어 회원이 한 가지의 등급을 가져야 하는 상황에서 여러 개의 등급을 가지고 있거나, 데이터를 삭제할 때 필요한 데이터가 같이 삭제되고, 데이터를 삽입하는데 하나의 필드값이 NULL이 되면 삽입이 안 되어서 삽입하기 어려운 현상을 말한다.&lt;/p&gt;
&lt;p&gt;정규화는 정규화 원칙을 기반으로 정규형을 만들어가는 과정이며, 정규화된 정도를 정규형으로 표현한다. 기본 정규형은 &lt;strong&gt;&lt;em&gt;제 1정규형, 제2 정규형, 제3 정규형, 보이스-코드 정규형(BCNF)&lt;/em&gt;&lt;/strong&gt;이 있고, 고급 정규형으로는 &lt;strong&gt;&lt;em&gt;제4 정규형과 제5 정규형&lt;/em&gt;&lt;/strong&gt;이 있다.&lt;/p&gt;
&lt;h2&gt;정규형 원칙&lt;/h2&gt;
&lt;p&gt;정규형의 원칙은 데이터베이스 설계에서 데이터의 중복을 최소화하고 데이터의 무결성을 보장하기 위해 정의된 일련의 규칙입니다. 주로 관계형 데이터베이스에서 사용되며, 데이터베이스의 효율성과 유지보수성을 높이는데 도움이 된다.&lt;/p&gt;
&lt;h3&gt;제1 정규형(1NF)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;각 테이블은 원자적인 값만을 포함해야 한다. 즉, 더 이상 나눌 수 없는 단위여야 한다.&lt;/li&gt;
&lt;li&gt;각 속성은 하나의 값을 가져야 하며, 여러 개의 값을 포함하는 복합 속성은 허용되지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/566f6a57ebf3953a555f1e0af7174b9c/bbbf7/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.294117647058826%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAABTklEQVR42q1S266CQAz0/3/JB1QS3zAqEAHBqFxVVLxw8ZY5mSaYQzThxU2W7XbLtJ1pBz9eHX7KsoTruvA8D/v9Huv1GsvlEufzGYfDQe66riNNU3k/nU5iLxYL7HY7uTcA6ZjP57KDIMBkMsF4PIbv+9A0DcPhEN1uF6qqYjabyVYUBYPBAL1eT2IbgM/nE1VVSaX3+x15nuNyuYhNf5ZlOB6PuF6vEsuqN5vN+2TVDcC29Xq9pIswDIWGVg7bFqt6PB643W5itwKyNWaP41gqIOHb7VYoIAhbIp81BUVRyEl/bX+IUpPNH6fTqQjDJBRpNBqJAJwCvtNHm4IYhoEkSYSWNyBFYHUE4Bg4jgPbtsWuExDUsiyJoxCr1Qr9fh+maYo4XwGjKJI2OF8EZesMZjUcDQIxCf30cYxY4QfgN1XrgJpj7v8+2t9E+gNLQEV5i6KY7QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;제 1정규형&apos; title=&apos;&apos; src=&apos;/static/566f6a57ebf3953a555f1e0af7174b9c/ca1dc/2.png&apos; srcset=&apos;/static/566f6a57ebf3953a555f1e0af7174b9c/e7570/2.png 170w,
/static/566f6a57ebf3953a555f1e0af7174b9c/f46e7/2.png 340w,
/static/566f6a57ebf3953a555f1e0af7174b9c/ca1dc/2.png 680w,
/static/566f6a57ebf3953a555f1e0af7174b9c/02d09/2.png 1020w,
/static/566f6a57ebf3953a555f1e0af7174b9c/bbbf7/2.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;제 1정규형&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그림처럼 두두라는 브랜드에 판매 제품이 반바지, 트레이닝복 세트 이렇게 있을 때 이것을 나눠서 반복 속성을 제거하는 것을 볼 수 있다.
구찌라는 브랜드도 마찬가지로 셔츠와 정장세트를 나눠서 반복 속성을 제거해준 것을 확인할 수 있다.&lt;/p&gt;
&lt;h3&gt;제2 정규형(2NF)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1NF를 만족해야 한다.&lt;/li&gt;
&lt;li&gt;기본 키가 아닌 모든 속성들이 기본 키 전체에 대해 완전 함수 종속해야 한다. 즉, 기본 키 중 어떤 부분에도 의존하지 않아야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/18cbcdb689375be978972e9e2eb22eb4/bbbf7/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.294117647058826%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB2UlEQVR42o1Sa2/aUAzt//81+7BJE9I2oaUMlQwySKAhSUsIeRFoyQNu3mf23YpWTVpnybnXsX1sH98bkHRdhyzLpFZVBSEEzucz2raVvrIskaaptP/Uy+Vyvb/IDX/yPIdhGFLDMMRiscB8Psd+v5eq6zqGwyGCIEAURYjjGLvdDqPRCJZlIUmSK6gE5G4YyPd9HA4H2LYtlQO3260En81mWK1WMo6LuK4LRVGwXC5lzivAoihkRQ5iJydylwzI3ZimifF4LGO4QwZcr9cYDAZQVfVvQOaprmvJHzv4ZN6appE2c8tJQvzmjP4L4o955ek47hWH/5KeJ6Akn/hjrt+SNwG7qkT+/IQiPaGvK7IFjvsYIkvRk68thfR1dNKovwBF2cDZ+LAfPMRJCj86wqJ73XRoYw+PEwWb799QeQ5OlgF18OFqR/oU008f8WzqsoAEPKYCP9YRtHsflneCqm+gqCbyM3GY+AgpKTRmKHcP8LQ7OJNbOOoIqbNCZGjQvgyQ3M8BmkACcieFqJEXJUTV4pSdcXjKaAE9miRAsJjC1SZoQhcnm17A18+yANvW3S2U9+/gzVWgrf9jKR1tlSqzgu4NjSUutFl6CX3boKbXUNL2a/rPK/wJTcVAaWaqRnAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;제 2정규형&apos; title=&apos;&apos; src=&apos;/static/18cbcdb689375be978972e9e2eb22eb4/ca1dc/3.png&apos; srcset=&apos;/static/18cbcdb689375be978972e9e2eb22eb4/e7570/3.png 170w,
/static/18cbcdb689375be978972e9e2eb22eb4/f46e7/3.png 340w,
/static/18cbcdb689375be978972e9e2eb22eb4/ca1dc/3.png 680w,
/static/18cbcdb689375be978972e9e2eb22eb4/02d09/3.png 1020w,
/static/18cbcdb689375be978972e9e2eb22eb4/bbbf7/3.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;제 2정규형&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그림을 확인해 보면 기본키인 {브랜드, 제품명}과 정말 종속되어 있는 브랜드번호 릴레이션과 {브랜드, 제품명}에 따른 가격 릴레이션으로 분리되어 있는 것을 확인할 수 있다. 주의점으로는 릴레이션을 분해할 때 동등한 릴레이션으로  분해해야 하고, 정보 손실이 발생하지 않는 무손실 분해로 분해되어야 한다는 점이다.&lt;/p&gt;
&lt;h3&gt;제3 정규형(3NF)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;2NF를 만족해야 한다.&lt;/li&gt;
&lt;li&gt;기본 키가 아닌 모든 속성들이 기본 키에 대해서만 종속되어야 한다. 즉, 기본 키가 아닌 속성들 간에는 종속 관계가 없어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;이행적 함수 종속&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e7ed479798da5b6b84ce58d7c9348477/f8db4/7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 87.64705882352942%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAIAAADUsmlHAAAACXBIWXMAAAsTAAALEwEAmpwYAAACG0lEQVR42qVTWU/bQBDO/3+p1IoHRIECRuWhKupTlABZJ22IBA7YaUGiahIf8ZEDH7HXx+7a6ThLgaYUKvXTyJqd3W/225lxZfE7iqLI87z4BR7kkcUfqKzEsiyTJKlarSqKcnraPj8/6/f7CCFFlgkhD3dwMmRN0yzNyL3Nbl1DN8IoMk1rPJ64nm9aNnwjHGeEwgH4ciGVMMSUEEYJJRkYOKxcsCQFEZCLwmL5mDLMDeMY46Qku968c+3UuyOx5yDFqknGtTrjwnh61fEh2JAt1HOOL0ZItoIwARUl2XRmAhpsI+P14eV69WbjWKue6UBkrCC0rFT7m7VeH27Uvr/6IG0jffNoYNhemiScfPu+pe61zLVP8tvaDWSBe0pyXlAGWovOlb11om0d/XjzsSu0Ru8aquF4CSe7btC5supdQ+zZSDbrkr4iW3N82IUXNb86J5em2DPnUYK57HmIwSuBSySlE0OQWzCPKGO8PaDlzmF5GOGSvByMO4PtlOT3hwDQRRynfHigLU+QVyaMsJyXajkzxA+imY8nXmRN51MvcgNMKQuj+Any4xRhTBmlXxR9p6Hui+p+UxVEVUBDZxrEvGCLv4NSGA2KLjShZe42BmuH3YO2JTT1h2ovngWQP8v6DtKFpraLhkLT2EOqPQ3+iQxvnsx83fE12wNTLW809uMkg6F+mQx9gsLCf5M+MphNQunL5OfxX+SfFJj2rslxoy0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;이행적 함수 종속&apos; title=&apos;&apos; src=&apos;/static/e7ed479798da5b6b84ce58d7c9348477/ca1dc/7.png&apos; srcset=&apos;/static/e7ed479798da5b6b84ce58d7c9348477/e7570/7.png 170w,
/static/e7ed479798da5b6b84ce58d7c9348477/f46e7/7.png 340w,
/static/e7ed479798da5b6b84ce58d7c9348477/ca1dc/7.png 680w,
/static/e7ed479798da5b6b84ce58d7c9348477/f8db4/7.png 724w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;이행적 함수 종속&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;이행적 함수 종속이란 A -&gt; B와 B -&gt; C 존재할 때, 논리적으로 A -&gt; C도 성립하는데, 이때 집합 C가 집합 A에 이행적으로 함수 종속이 되어있다고 말한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;예를 들어 dudu라는 패션 플랫폼이 있다고 가정하고, 각각의 브랜드의 등급, 수수료율이 정해져 있는 테이블을 아래의 그림과 같이 분해하는 것을 말한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a901f9da298f893cbadc1d5beacbde34/bbbf7/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 67.64705882352942%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAACE0lEQVR42q2U627aQBBG8/7P0x+JmtDmRqKQEFzAYIMBO4GAE9+N8XVP10CkVC1RpXak1Xg9njPfzqx8xH+2o48bP0hQB2NGY4sgTPF8uR8aLJYuUZwznc3p9XU0fUpZis+BlRCMph6NC4XLGxV94nP3YPDluMn5dQ/NcGn/sDg5a9F6nBHKArUJcQAoZGSximm1NTpdqcpOULpTrpqKBA+x5gFTS0KVMaZ8Xid74EGFlcAwAy6bKhfNHuNZgNKfc3J6J4sYUrFHb7iU8T6q/koYpZ8rrC3Z5MTrbLtqBfWK41T2L9367drHirI63MP6uEL83uQ6J8tyzNmMycTAssxf4u95H3OP/lTlPVyrEO+J2/fiL65NVbGJI9y3V9JkjSjkcdKUwHXINwmiLPZVCrIkIvAc2XA5kDIjClx8V/bTd+op7IBl4GCrHdpnx7xpXbL5FEfv0fn+lZfuA4Wz2vHiZ5ajW7q3xxSuTuWPeZ3cM7w/ZaE1IQ92wMJ7IxyraDfnhJMhuQSa7Vt6l2dMW9dk9mL7Ye7NMDoNxso3XLMNgcHGHmCqV5Sehti4O2AugZExQJGKfAmugat+Z7t/6tyRO8vdtYqesfoX6I8N4kUX4RskK5WnQZPS0ag23l5h5LN5saR8jbX0mT3f+hddJXyaUITubiCJTWyPcJ5VisBCyAK5ZxIuR1SBicjCw1P+l5/DT7eTK/usCGpxAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;제 3정규형&apos; title=&apos;&apos; src=&apos;/static/a901f9da298f893cbadc1d5beacbde34/ca1dc/4.png&apos; srcset=&apos;/static/a901f9da298f893cbadc1d5beacbde34/e7570/4.png 170w,
/static/a901f9da298f893cbadc1d5beacbde34/f46e7/4.png 340w,
/static/a901f9da298f893cbadc1d5beacbde34/ca1dc/4.png 680w,
/static/a901f9da298f893cbadc1d5beacbde34/02d09/4.png 1020w,
/static/a901f9da298f893cbadc1d5beacbde34/bbbf7/4.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;제 3정규형&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;보이스-코드 정규형(BCNF)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;모든 결정자(Candidate Key)가 키 전체에 대해 함수 종속되어야 한다.&lt;/li&gt;
&lt;li&gt;제3 정규형을 만족하면서 부분적으로 함수 종속되는 문제를 해결한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;결정자&lt;/em&gt;&lt;/strong&gt; : 함수 종속 관계에서 특정 종속자(dependent)를 결정짓는 요소이다. 예를 들어 A -&gt; B일 때, A는 결정자, B는 종속자이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;dudu 플랫폼에서 브랜드별 이벤트를 진행한다고 했을 때, 요구 사항은 다음과 같다고 가정해 보겠습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;각 이벤트에 대해 한 명의 고객은 오직 하나의 브랜드의 이벤트만 참여할 수 있다.
(ex : &lt;strong&gt;&lt;em&gt;만약 1번 고객이 구찌의 모자 이벤트를 참여했다면, 아미의 모자 이벤트는 참여할 수 없다.&lt;/em&gt;&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;각 브랜드는 하나의 이벤트만 진행할 수 있다.&lt;/li&gt;
&lt;li&gt;하나의 이벤트는 여러 브랜드가 담당할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/022ec9a40aa45264c71e059e5af97b1d/bbbf7/5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 48.23529411764706%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABhElEQVR42pWSW2/TQBCF8///BxLigUdQeapKUwQtTRMDIWlTx7k4di62185lY6/3Y7LhJlEQWeloVjuzZ8/ZmQayrLUO/9r/72qcUlxbQ232glJQ/Z0wSRLiOHZqlFLEUeyS6/WaLMu+k8FO3bNPb9lnd2zTNkbIXa6Wh+r6SFgZS7jICWYrFkrTfRhx0/7CbFkwihL6fsi2FOvCuMk+c/7xBa+unhFOLsHoPxUaKVSbkrTYSdzTHwR43T7RSjFPCoaTiNIcVFi06jKPm0RRk2J5gxXb+U7ReriiN/Gc0kYpSlfbinmuJRp6w5BOzydMN8wEvijfSU1tanT+lTi8YDq+QC2uMVVJUiQ0vTd0Ht+7P25UiyXhbZug5bHsDfDO3/Lh9Rnju0+M5Kx7+Y5i4Mt/1c5y03vJ2fVzpmLZPmk5z8kefRI/oBhPSf0h2TAgH01QwdjtdRS5puj8nlK1qFQbnXV+NuX38TppbA4EptyI1QM0T43okdAeX/kRf4HjpROG+xuL/wEKj3wl+QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;회원번호 - 이벤트명 - 브랜드의 릴레이션과 함수 종속&apos; title=&apos;&apos; src=&apos;/static/022ec9a40aa45264c71e059e5af97b1d/ca1dc/5.png&apos; srcset=&apos;/static/022ec9a40aa45264c71e059e5af97b1d/e7570/5.png 170w,
/static/022ec9a40aa45264c71e059e5af97b1d/f46e7/5.png 340w,
/static/022ec9a40aa45264c71e059e5af97b1d/ca1dc/5.png 680w,
/static/022ec9a40aa45264c71e059e5af97b1d/02d09/5.png 1020w,
/static/022ec9a40aa45264c71e059e5af97b1d/bbbf7/5.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;회원번호 - 이벤트명 - 브랜드의 릴레이션과 함수 종속&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;위 릴레이션을 보면 {회원 번호, 이벤트명} 또는 {회원 번호, 브랜드}가 후보키가 되며, 만약 나이키라는 브랜드가 신발 이벤트를 진행할 때, 이를 삽입하면 회원 번호가 NULL이 되는 문제가 발생한다.&lt;/p&gt;
&lt;p&gt;함수 종속을 확인해보면 브랜드가 결정자지만 후보키가 아니므로 브랜드 속성을 분리해줘야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4a6bf86f51b70b134fe9f6f1518b195d/bbbf7/6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 48.23529411764706%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABn0lEQVR42pWSa4+aQBSG+f9/qemHJm3TdLde1uKKrnhBRVAZbgMOMDwd2GTJJv3iJCfnQuYh75nX4sHT6halKpq6QTeauq7NcPhuPQqMxJW5M+N49vCDA8u3V4pSDsA0SeiiqStknpGmiflzTVHIvtdNQ9u2JnR/ISsSrumZ9B5xvhngZk6h8gHouGZoQmQK23F5Gs/62t37rDZH8kIZSYOmDhiII3Fxxb96LLdzM0sHoMgVsVR02XH3vMxXhEJyCgWefyMva6o8QV48lEypqhopc5MrEqMsCM59/QG8pIpLWhLJGmdzYGwv+97rgIEgV5ridkKsp5TxhdqsIAgD9vsdZVkgzWq8g9fn7oEsf77AXyyJdwf+fv/J05evhCuX/czGHU3I/ACtB8kivTF9/cOP3996yVEeMluMuMQnynuJ5Y2mHGyH62rD1uxv/TwmcNYczWw3sZHbXf8gbdv0wDiLcNY2z5NfZjUnsrvgbbsgykLuHfBR22R5ymrt8GJPEPGNTCZ9n2TC+FNhvVviXdLn+pNfP47Wujf0/6K7+w9tEP4KXR+reAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;보이스 - 코드 정규형을 만족한 릴레이션&apos; title=&apos;&apos; src=&apos;/static/4a6bf86f51b70b134fe9f6f1518b195d/ca1dc/6.png&apos; srcset=&apos;/static/4a6bf86f51b70b134fe9f6f1518b195d/e7570/6.png 170w,
/static/4a6bf86f51b70b134fe9f6f1518b195d/f46e7/6.png 340w,
/static/4a6bf86f51b70b134fe9f6f1518b195d/ca1dc/6.png 680w,
/static/4a6bf86f51b70b134fe9f6f1518b195d/02d09/6.png 1020w,
/static/4a6bf86f51b70b134fe9f6f1518b195d/bbbf7/6.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;보이스 - 코드 정규형을 만족한 릴레이션&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;위 그림을 확인해 보면 나이키의 신발 이벤트가 정상적으로 들어갔으며 회원 번호와 브랜드. 이벤트명과 브랜드로 잘 나눠진 모습을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;정규형의 원칙을 따르면 데이터의 중복을 최소화하고, 데이터의 일관성과 무결성을 유지할 수 있다. 하지만 &lt;strong&gt;&lt;em&gt;과도한 정규화는 성능 저하를 초래할 수 있으므로&lt;/em&gt;&lt;/strong&gt;, 실제 서비스 운영 환경에서는 성능과의 균형을 고려하여 적절한 정규화 수준을 선택해야 한다. 또한, 정규형을 만족하지 못하는 경우에는 데이터의 수정, 삽입, 삭제 시 데이터 무결성을 유지하기 어려울 수 있으므로, 정규형을 따르는 것이 좋다고 생각한다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[ERD에 대한 간단한 설명(Entity Relationship Diagram)]]></title><description><![CDATA[ERD 의미 ERD(Entity Relationship Diagram…]]></description><link>https://hoonblog.netlify.app/entity-relationship-diagram/</link><guid isPermaLink="false">https://hoonblog.netlify.app/entity-relationship-diagram/</guid><pubDate>Fri, 21 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f611ea6d1f1fde2595947173da7d1b5b/4c79d/1.webp&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.47058823529413%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/webp;base64,UklGRo4AAABXRUJQVlA4IIIAAABwBACdASoUAA0APtFUo0uoJKMhsAgBABoJQBYheABi29bNdQlRGEy9gGH6+AD+7e2BaFk2qrxGRNlXQRyq0IYW50JxiHjQbj1mGrKrEH8Ef+AZMYfSE4UtUbBt3Md2RgLdo6VesvM8wSJvrBPKbBbsnNCa+TzEGeMxW0Th2HiyOBAA&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://gitmind.com/kr/er-diagram-tool.html&apos; title=&apos;&apos; src=&apos;/static/f611ea6d1f1fde2595947173da7d1b5b/4c79d/1.webp&apos; srcset=&apos;/static/f611ea6d1f1fde2595947173da7d1b5b/33073/1.webp 170w,
/static/f611ea6d1f1fde2595947173da7d1b5b/719ab/1.webp 340w,
/static/f611ea6d1f1fde2595947173da7d1b5b/4c79d/1.webp 680w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://gitmind.com/kr/er-diagram-tool.html&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h2&gt;ERD 의미&lt;/h2&gt;
&lt;p&gt;ERD(Entity Relationship Diagram)는 &lt;strong&gt;&lt;em&gt;데이터베이스를 구축할 때 가장 기초적인 뼈대 역할을 하며, 릴레이션 간의 관계들을 정리한 것이다.&lt;/em&gt;&lt;/strong&gt; 설계 과정에서 중요한 도구로서 데이터베이스의 구조를 이해하고 분석하는 데 도움을 주며, 데이터베이스의 효율성과 일관성을 유지하고 향상하는 데 기여한다. 또한 팀 간의 협업과 유지 보수를 간편하게 만들어준다. 따라서 프로젝트의 성공을 위해 ERD를 적절하게 활용하는 것이 중요하다. 만약 우리가 서비스를 구축한다고 하면 가장 신경 써야 할 부분이다.&lt;/p&gt;
&lt;h2&gt;ERD의 중요성&lt;/h2&gt;
&lt;p&gt;ERD는 시스템의 요구 사항을 기반으로 작성되며 이 ERD를 기반으로 데이터베이스를 구축한다. 데이터베이스를 구축한 후에도 디버깅이나 비즈니스 프로세스 재설계가 필요한 경우에 설계도 역할을 담당한다.&lt;/p&gt;
&lt;p&gt;하지만 ERD는 관계형 구조로 표현하는 데이터를 표현할때 유용하지만, 비정형 데이터를 표현할 수는 없다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;비정형 데이터&lt;/em&gt;&lt;/strong&gt;란? 비구조화 데이터를 말하며, 미리 정의된 데이터 모델이 없거나 미리 정의된 방식으로 정리되지 않은 정보다. 이러한 데이터는 일반적인 행-열 구조가 없으며, 데이터베이스나 테이블 등으로 쉽게 정리하거나 저장하기 어렵다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;비정형 데이터는 사람의 언어, 이미지, 비디오, 소셜 미디어 게시물, 웹 페이지 등 다양한 형태로 존재한다.&lt;/p&gt;
&lt;h3&gt;데이터베이스 구조 시각화&lt;/h3&gt;
&lt;p&gt;복잡한 데이터베이스 구조를 시각화하여 이해하기 쉽게 도와준다. 개체(Entity)와 개체들 간의 관계를 명확하게 보여주기 때문에 데이터베이스의 구조를 파악하는 데 도움이 된다.&lt;/p&gt;
&lt;h3&gt;요구 사항 분석&lt;/h3&gt;
&lt;p&gt;ERD를 작성함으로써 요구 사항을 명확하게 파악할 수 있다. 데이터베이스 설계는 사용자 요구 사항에 기반해 이루어지며, ERD를 통해 개체들의 속성과 관계를 정확히 정의함으로써 프로젝트의 성공 가능성을 높일 수 있다.&lt;/p&gt;
&lt;h3&gt;데이터 일관성 유지&lt;/h3&gt;
&lt;p&gt;데이터베이스의 구조를 명확하게 정의함으로써 데이터의 일관성을 유지하는 데 도움이 된다. 올바른 관계를 설정하고 적절한 속성을 지정함으로써 데이터의 중복을 줄이고 무결성을 유지할 수 있다.&lt;/p&gt;
&lt;h3&gt;데이터베이스 효율성&lt;/h3&gt;
&lt;p&gt;올바른 ERD를 사용하면 데이터베이스의 성능과 효율성을 향상할 수 있다. 적절한 인덱스를 설정하거나 쿼리 최적화를 수행하는 등 ERD를 기반으로 데이터베이스를 튜닝할 수 있다.&lt;/p&gt;
&lt;h3&gt;개발자와 협업&lt;/h3&gt;
&lt;p&gt;ERD는 개발자, 데이터베이스 관리자, 프로젝트 관리자 등 다양한 팀원들 사이의 소통과 협업을 간소화할 수 있다. ERD를 통해 모든 팀원들이 데이터베이스 구조를 쉽게 이해하고 작업할 수 있다.&lt;/p&gt;
&lt;h3&gt;유지 보수 용이성&lt;/h3&gt;
&lt;p&gt;데이터베이스가 변경되어야 하는 경우에도 유지 보수를 용이하게 만든다. 데이터베이스 구조를 시각화하고 문서화하면 변경 사항을 파악하고 적용하는 데 도움이 된다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[컴퓨터의 요소]]></title><description><![CDATA[컴퓨터는 CPU, DMA 컨트롤러, 메모리, 타이머, 디바이스 컨트롤러 등으로 이루어져 있습니다. CPU CPU란 (Central Processing Unit…]]></description><link>https://hoonblog.netlify.app/computer-elements/</link><guid isPermaLink="false">https://hoonblog.netlify.app/computer-elements/</guid><pubDate>Mon, 17 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;컴퓨터는 CPU, DMA 컨트롤러, 메모리, 타이머, 디바이스 컨트롤러 등으로 이루어져 있습니다.&lt;/p&gt;
&lt;h2&gt;CPU&lt;/h2&gt;
&lt;p&gt;CPU란 (Central Processing Unit)의 약자로 중앙 처리 장치라고 부르기도 하며, 제어장치, 레지스터, 산술논리연산장치로 이어져 있습니다. 컴퓨터의 두뇌로서, 명령어를 해석하고 실행하는 역할을 수행합니다. 산술 및 논리 연산, 데이터처리, 제어 등의 작업을 처리합니다. &lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d2c8624f7665321901871b1464a9e4cb/5b101/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 78.23529411764706%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsTAAALEwEAmpwYAAADr0lEQVR42mWU+VPbRRiH80/pKOo4dRT7U3/oTG1LpZwWylAORaAJEEIKpKAcKUcgIQlHGkIOAiQBEsJVwo1Mp4PKOFY71kod5RpazuRx+QawHXZmj9nd99nP7rvvKyMSQarhMOGjIw4PDsQwzGk5PNjj919+JOgfwmbrYWlhXsxG90bCR5zZn1TZcSMtHk+cQvZ3efbrKn6fm5aGWjTlaqqrqqipraVUWUJXUyX7O5vS3sjR4XmgtCBOW3v+jDG/F52AVNwrQ1NZiVarRd/agt5gpK3NiL7NjFwux1ij4HB3+wT6v1JZRFxveWlBgpSrSykXaurq6mhp0WEwGCRAi8GMyaDDaDTiNd7F1laDUqXGUF0ooFtETgRJwOXlx9zJyqJeKGnW6dDr9ZIanaFDUvSwWU2/XsGwIRdfQxpuSz0j2utYzHrKVCr0Arq3/c/ZLWUzAQdpqUmYze2YjG0YTR10GB7gai2hr0PDhPYyU7prDOluM+muJfQwn4AuBWu7jh5HLyplsaR0f2dDgsqGjQpyEy6iLtfgdPWKk1txlQuIV8tg93eMmgsJNX2Bw27B7uxnaNCJy2nD1uPAZrXicLooK1NFoa82kS1ODVOV+TGZ6alYbXY8vd2MNt6kv7OeYFMKg+0qRvr0uF0O3G43DocblzjY6XRgtztE72TA4yUrK5OFuWlkW9s7dNVkIP/qImXqCsbGHzE93s9Pk43MDzfg83nx+AJS7/WKsWeAgf5+vD4fXo8Hk8lMcYmS63HxLC0uiW8jyvSED21eLHfSk3H1upmZnWN0YprgeIjR0SDBYIBAIIDf72dsbEwaWywWCuRKUpMSyP7yAg8KLrH28u8ocHP7NfamPCqyL6EoLuXJk8csLS0yPz9HKBRiamqK2dkZHk1O0NnZSX6hgvgbcRQmf07FrXdRp72PzfR91CmRkzCbmfRjrbzMNxkJ2F19/Pn8D1ZWVlhd/VlcZRFrdzd5+XJSb8aRE/8ZNRnvoboVw31lhlA+zOvd/beB6xs79LYp6Ki+hvxuoQCt8tvTp3TbneQXFHLj6hVK0mJRJb+DJj0GRW4yPvGm/66fRMuboXcK/WFugp7mJHKzMygqKkahKOJ24hXxRrE0fv0h3ybGUFaQIrzrYn09GstR+6O3Y/kUuLf7SnwDN5Wa+1wVij746BOK0z5Fk3OBnMxE8WUcvHjx8kzRsZ1key45vFlFZK6t/cWI8GSv8LjF0iXSlpWNja0zRdHUFT6Xuo6B/wEMovHsK3ODmQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/d2c8624f7665321901871b1464a9e4cb/ca1dc/1.png&apos; srcset=&apos;/static/d2c8624f7665321901871b1464a9e4cb/e7570/1.png 170w,
/static/d2c8624f7665321901871b1464a9e4cb/f46e7/1.png 340w,
/static/d2c8624f7665321901871b1464a9e4cb/ca1dc/1.png 680w,
/static/d2c8624f7665321901871b1464a9e4cb/5b101/1.png 773w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;레지스터(Register)&lt;/h3&gt;
&lt;p&gt;CPU 내부에 위치한 작고 빠른 기억 장소로, 명령어와 데이터를 일시적으로 저장하는 역할을 합니다. 레지스터는 CPU에서 가장 빠른 액세스 속도를 가지므로, 중앙 처리 장치와 메모리 간의 데이터 이동을 감소시키고 연산 속도를 향상시킵니다. 또한 주소 레지스터, 데이터 레지스터, 명령어 레지스터 등 다양한 유형의 레지스터가 있습니다.&lt;/p&gt;
&lt;h3&gt;산술 논리 연산장치(ALU, Arithmetic Logic Unit)&lt;/h3&gt;
&lt;p&gt;산술 연산(덧셈, 뺄셈 등)과 논리 연산(AND, OR, NOT 등)을 수행하는 장치입니다. ALU는 레지스터에서 데이터를 받아서 연산을 수행하고, 그 결과를 다시 레지스터에 저장합니다. 이를 통해 데이터의 처리, 비교, 조작 등 다양한 연산을 수행할 수 있습니다. ALU는 CPU의 핵심적인 구성 요소 중 하나로, 컴퓨터의 계산 능력을 결정하는 요소 중 하나입니다.&lt;/p&gt;
&lt;h3&gt;제어장치(Control Unit)&lt;/h3&gt;
&lt;p&gt;CPU의 구성 요소 중 하나로, 컴퓨터 시스템의 모든 동작을 조정하고 제어하는 역할을 합니다. 명령어 해석, 실행, 데이터 전송 등의 작업을 수행합니다. 제어장치는 명령어를 해독하고 실행 단계를 조정하여 다른 하드웨어 구성 요소들이 올바른 순서로 동작하도록 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 469px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4dc6ccd44a7cce685dde1093325d6c7a/44038/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 110.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAWCAYAAADAQbwGAAAACXBIWXMAAAsTAAALEwEAmpwYAAAENklEQVR42pWV+U8cZRjH+4dZE7Gp5SyoNRZEOYyNGq8EKK3lJoXlFCwWW39QJI1KKIS0sMe8s/cK7MXs7MHuAlvEAnLuUXZBA1+fmVnKgmlS3+TJM/PmfT/zfZ/3+75zDlI7Ag4Pj5RHJWEreQDH+g7mNqIQNuPwbCUox+CkvvBOAplNmpOejnNpHnUe4SlNFBY34KUwL6xjfGENo/5lDGhM6PhtAkPTHoyHVzEVXoOHxggLGwit7GD/4J9jXQpQakMaPy43apBbr0VWzSTqR9ywbe5As7SKEZcfQzaC+RZhWt/GA/cT5DfokFunRc4tNarvWbG+nThRaPH8iazrkyho4lHUwqOgkaG024zaB05U/exEy5gAFhRwe9yN6mEXPvl+GvmNHI1nKGzmcb5qCs3D9hPg3QkRF26o8RbBCqVBFAUNHCnQ4eJNHYpVWpi9WnzYq8Mb9P52C8PVNr0cxe16XGnlUdFtRPxZSgHeGffgtetT8hdz6rnnkU9KCxp5lKh4qF08rrbzeLWGQcsEbMyHEBHmseoPYm7Gh8++NWM7tncCfL12Ch/1mHCtx0jZKOfyTgPyGkhNO4PBy/CLkeG7xxxCoohYwAeB57Dt92DZM48v7kjApALspxrlfK1B0BVANBzCX/T1GOUZqyirLukgoMhwX83QMcrDPW2Hj2khMA4LVgNEqx1fDliwFd3LANJuLXtDOHiyiN1gEIcrS3BN+6gUUuEZNC5F6fkqDiOPXJh3Bgjsg9fhh14v4NN+038VLgkBRKZtMDwcw5rgRnDOi7ZfGfonGEy05LJuJpfgcpOUlRpLkU31LusyIBpPA/seCrKn3BY7AmYjnDodghYrPLMO/KDhMaxnsPgZ3u9i5FOGomZFtRRFLQpcBiaSp5e86g8BTyM4WF4CViMQZ/24UMvITrSzboaKXlLUwGQPHjshl+LiLR3KOs8AL91UQ0N2mKWNsJo8cNi8GJ10yZvyXqcClGtYzeH+iB0zNqqdQYTN4sNjrUC2yahhpg9zJUOnI4+UyLZRMTCBoXeM4cZPHDwOAYmAgFjQh6jfjRVBRM2gFZvRvdPAN+mkSAU/jsImduJDss2YjeFHxiA6nQhZrVh02BG0miD+7kT1oO3lgcUqZckllF8h26g5AXuRCNYDYUQXlxCem8dXA2byYfL/Act76J12uVSlRyXtagWFlEvpPFfSWd6NZwCzXgIo+VCyjXQbSf15DYoPL9VxKCfwc+C9RyIB6bZp1b+whtJJ+aD7RT4k9V1GJFP7CtAf2SRjq5Fdp9xxxydAes6uoyWSbYx0Uiq/kdSwM2PoBqqexOCER7kPj/8hprk/8HGfCe/eJkXpKKZ4p5XhWh+Djq6vzwcYrpCi4raTMaV0td0lWHL/IOOfkqam9v+WzbkTT52K7VgKu4kUtmJn+iniz/bl+Wld+BdUflHCRXtRRwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://blog.naver.com/dlaxodud2388/221613076571&apos; title=&apos;&apos; src=&apos;/static/4dc6ccd44a7cce685dde1093325d6c7a/44038/2.png&apos; srcset=&apos;/static/4dc6ccd44a7cce685dde1093325d6c7a/e7570/2.png 170w,
/static/4dc6ccd44a7cce685dde1093325d6c7a/f46e7/2.png 340w,
/static/4dc6ccd44a7cce685dde1093325d6c7a/44038/2.png 469w&apos; sizes=&apos;(max-width: 469px) 100vw, 469px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://blog.naver.com/dlaxodud2388/221613076571&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;CPU의 연산 처리 순서&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;제어장치가 메모리에 계산할 값을 로드한다. 또한, 레지스터에도 로드 &lt;/li&gt;
&lt;li&gt;제어장치가 레지스터에 있는 값을 계산하라고 산술논리연산장치(ALU)에 명령&lt;/li&gt;
&lt;li&gt;제어장치가 계산된 값을 다시 레지스터에서 메모리로 계산된 값을 저장&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;인터럽트(Interrupt)&lt;/h2&gt;
&lt;p&gt;인터럽트란 컴퓨터 시스템에서 발생하는 이벤트로, 어떤 신호가 들어왔을 때 CPU를 잠시 정지시킨 후 우선 순위가 더 높은 작업을 처리하도록 하는 메커니즘입니다. 인터럽트는 외부 장치의 상태 변화나 예외 상황 발생 등 다양한 상황에서 발생할 수 있다.&lt;/p&gt;
&lt;p&gt;인터럽트가 발생되면 인터럽트 핸들러 함수가 모여 있는 인터럽트 백터로 가서 인터럽트 핸들러 함수가 실행됩니다. 인터럽트 간에는 우선순위가 있기 때문에 우선순위에 따라 실행됩니다. 인터럽트는 소프트웨어 인터럽트와 하드웨어 인터럽트로 나눌 수 있습니다.&lt;/p&gt;
&lt;h3&gt;하드웨어 인터럽트&lt;/h3&gt;
&lt;p&gt;하드웨어 장치에서 발생하는 인터럽트로, 주로 외부 장치가 CPU의 관심이 필요한 작업을 알리는 역할을 합니다.  이때 인터럽트라인이 설계된 이후 순차적인 인터럽트 실행을 중지하고 운영체제에 시스템 콜을 요청해서 원하는 디바이스로 향해 디바이스에 있는 작은 로컬 버퍼에 접근하여 일을 수행합니다. 예를 들어, 키보드 입력, 마우스 클릭, 타이머 등이 있습니다.&lt;/p&gt;
&lt;h3&gt;소프트웨어 인터럽트&lt;/h3&gt;
&lt;p&gt;소프트웨어에서 발생하는 인터럽트로, 트랩(trap)이라고 부르기도 하며 주로 프로그램 실행 중 예외 상황이나 특정 이벤트에 응답하기 위해 사용됩니다. 예를 들어, 0으로 나누기 오류, 메모리 보호 오류, 시스템 호출 등이 있습니다.&lt;/p&gt;
&lt;h2&gt;DMA 컨트롤러&lt;/h2&gt;
&lt;p&gt;DMA(Direct Memory Access) 컨트롤러는 컴퓨터 시스템에서 데이터를 메모리와 주변 장치 간에 직접 전송하는 데 사용되는 하드웨어 장치입니다. DMA 컨트롤러는 CPU의 개입 없이 데이터 전송을 처리하므로, CPU가 다른 작업에 전념할 수 있도록 합니다.&lt;/p&gt;
&lt;p&gt;일반적으로, 데이터를 전송하는 과정에서 CPU는 데이터를 읽어오고, 그 다음 주변 장치로 전송하거나 메모리로부터 데이터를 가져와 주변 장치에 전송하는 역할을 수행합니다. 이렇게 CPU가 직접 데이터 전송을 처리하면 처리 속도가 느려지거나 CPU의 성능이 저하될 수 있습니다.&lt;/p&gt;
&lt;p&gt;DMA 컨트롤러는 이러한 문제를 해결하기 위해 도입되었습니다. DMA 컨트롤러는 CPU의 개입 없이 주변 장치와 메모리 간 데이터 전송을 수행합니다. CPU는 DMA 컨트롤러에 전송 작업을 지시하고, DMA 컨트롤러는 주변 장치와 메모리 사이의 데이터 전송을 독립적으로 처리합니다.&lt;/p&gt;
&lt;h2&gt;메모리(Memory)&lt;/h2&gt;
&lt;p&gt;메모리는 전자회로에서 데이터나 상태, 명령어 등을 기록하는 장치를 말합니다. 데이터의 읽기와 쓰기 작업을 수행하며, 프로그램과 데이터를 영구적으로 저장합니다.&lt;/p&gt;
&lt;h3&gt;주 기억장치 (Main Memory)&lt;/h3&gt;
&lt;p&gt;주 기억장치는 컴퓨터가 실제로 작동할 때 프로그램과 데이터를 저장하는 공간입니다. 주로 랜덤 액세스 메모리(RAM)이 사용됩니다. RAM은 읽기와 쓰기 모두가 가능하며, 전원이 공급되는 동안 데이터를 유지합니다. &lt;strong&gt;&lt;em&gt;주 메모리는 컴퓨터가 작동 중일 때만 데이터에 접근할 수 있으며, 전원이 꺼지면 저장된 데이터가 손실됩니다.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;캐시 메모리 (Cache Memory)&lt;/h3&gt;
&lt;p&gt;캐시 메모리는 CPU가 주로 사용하는 메모리 계층 중 하나로, 주 기억장치와 CPU 사이의 속도 차이를 극복하기 위해 사용됩니다. 캐시는 주로 속도가 빠른 SRAM(Static Random Access Memory)으로 구성되며, CPU가 자주 사용하는 데이터와 명령어를 임시로 저장합니다. &lt;strong&gt;&lt;em&gt;캐시는 CPU에 가까워 데이터 액세스 속도가 빠르며, 주 메모리로부터 데이터를 미리 가져와 CPU의 대기 시간을 줄입니다.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;보조 기억장치 (Secondary Storage)&lt;/h3&gt;
&lt;p&gt;보조 기억장치는 주 기억장치와는 달리 데이터를 영구적으로 저장하는 데 사용됩니다. 주로 하드 디스크 드라이브(HDD) 또는 고체 상태 드라이브(SSD)와 같은 장치를 의미합니다. 보조 기억장치는 주로 대용량 저장 공간을 제공하며, 컴퓨터의 운영 체제, 프로그램, 파일 등을 저장합니다. 보조 기억장치는 &lt;strong&gt;&lt;em&gt;주 메모리보다 접근 속도가 느리지만, 비휘발성이므로 전원이 꺼져도 데이터가 보존됩니다.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;각 메모리 유형은 속도, 용량, 비용 등의 측면에서 서로 다른 특징을 가지고 있으며, 컴퓨터 구조의 성능과 기능을 결정하는 요소 중 하나입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;타이머(Timer)&lt;/h2&gt;
&lt;p&gt;타이머는 몇 초안에는 작업이 끝나야 한다는 것을 정하고 특정 프로그램에 시간을 제한을 다는 역할을 합니다. 시간이 많이 걸리는 프로그램이 작동할 때 제한을 걸기 위해 존재합니다.&lt;/p&gt;
&lt;h2&gt;디바이스 컨트롤러(Device controller)&lt;/h2&gt;
&lt;p&gt;디바이스 컨트롤러는 컴퓨터와 연결되어 있는 입출력 디바이스들의 작은 CPU를 말합니다.&lt;/p&gt;
&lt;p&gt;reference : &lt;a href=&quot;https://blog.naver.com/dlaxodud2388/221613076571&quot;&gt;https://blog.naver.com/dlaxodud2388/221613076571&lt;/a&gt; , 면접을 위한 CS 전공지식 노트(저자: 주홍철)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[운영체제 (OS)]]></title><description><![CDATA[들어가며 운영체제(Operating System)는 줄여서 OS…]]></description><link>https://hoonblog.netlify.app/operating-system/</link><guid isPermaLink="false">https://hoonblog.netlify.app/operating-system/</guid><pubDate>Mon, 17 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;들어가며&lt;/h2&gt;
&lt;p&gt;운영체제(Operating System)는 줄여서 OS라고 부르기도 한다. 컴퓨터 시스템에서 하드웨어와 응용 소프트웨어 사이에서 동작하며, 컴퓨터의 자원을 효율적으로 관리하고 제어하는 소프트웨어입니다. 운영체제는 컴퓨터 시스템의 핵심 구성 요소로서, 하드웨어와 소프트웨어 사이의 인터페이스 역할을 수행하며, 사용자와 컴퓨터 시스템 간의 상호 작용을 지원합니다.&lt;/p&gt;
&lt;p&gt;우리가 알고 있는 대표적인 운영체제는 Windows, Linux, Mac OSX, iOS 등이 있다.&lt;/p&gt;
&lt;h2&gt;운영체제의 역할&lt;/h2&gt;
&lt;p&gt;운영체제는 시스템에서 중요한 역할을 수행하는 소프트웨어입니다. 주요 역할들을 설명해 보겠습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;자원 관리 : 운영체제는 컴퓨터의 자원을 효율적으로 관리합니다. 이는 CPU, 메모리, 저장장치, 입출력 장치 등을 포함합니다. 운영체제는 여러 프로세스 또는 작업이 공유 자원을 사용할 수 있도록 조정하고, 자원의 할당과 해제를 관리하여 시스템의 성능과 안정성을 유지합니다.&lt;/li&gt;
&lt;li&gt;메모리 관리 : 운영체제는 시스템의 메모리를 관리하여 프로세스가 메모리에 적절하게 할당되도록 합니다. 메모리의 주소 공간을 관리하고, 메모리 할당 및 해제를 처리하여 프로세스가 메모리를 효율적으로 사용할 수 있도록 합니다.&lt;/li&gt;
&lt;li&gt;파일 시스템 관리 : 운영체제는 파일 시스템을 관리하여 파일의 생성, 삭제, 읽기, 쓰기 등을 처리합니다. 파일과 디렉터리의 구조를 유지하고, 파일에 대한 접근 권한을 관리하며, 데이터의 안정성을 보장하기 위해 백업 및 복구 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;프로세스 관리 : 운영체제는 실행 중인 프로세스를 관리합니다. 프로세스 스케줄링을 통해 CPU 시간을 공정하게 분배하고, 프로세스의 생성, 종료, 일시 정지, 재개 등을 관리합니다. 이를 통해 다중 작업 환경에서 여러 프로세스가 동시에 실행될 수 있도록 합니다.&lt;/li&gt;
&lt;li&gt;입출력 관리 : 운영체제는 입출력 장치를 관리하여 프로세스가 입출력을 수행할 수 있도록 합니다. 입출력 장치의 드라이버를 관리하고, 입출력 작업을 대기시키고 완료된 작업을 처리하여 프로세스와 입출력 장치 간의 효율적인 상호 작용을 지원합니다.&lt;/li&gt;
&lt;li&gt;사용자 인터페이스 제공 : 운영체제는 사용자와 컴퓨터 사이의 상호 작용을 위한 인터페이스를 제공합니다. 이는 텍스트 기반 명령 줄 인터페이스(CLI)부터 그래픽 사용자 인터페이스(GUI)까지 다양한 형태일 수 있습니다. 사용자는 운영체제를 통해 프로그램 실행, 파일 관리, 시스템 설정 등을 수행할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;운영체제의 구조&lt;/h2&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/75156fc958ce07e15cdb83a119fce0fb/bbbf7/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 67.05882352941177%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAABd0lEQVR42q1Ty07CQBT164kLDQsfCx87N0aNbEBSKCSAGESkSCul4SEhVqS0pQ9C2k57LC0YDCEB4iR3XufOmXPv3NnDP7e9Wed54ULWLBRe+8i/dJErd/BY7UObOAHm7UIoKVOki22kCjyo3DvoYguKbgWY63mbEy4YrYEAM3eOb/oMo+wFzPwlLKkH18cIIb+HPN9/2dYS2sontGoco0ocajUBnXmAow0DjBB3B4VfAiTqGEIsivJVBMPUCRy5t0JoGAZkWYYkSVBVdT2hMx5AZ9PQuAzkWho6R4MYo1C9TUAcF5Y/siyLSqWCUqkEhmH+hD0nDG+fijwU6gjt2CFa9wdQ06d+Dj92D9kOFNJQ6hkobzQMLgvHkFcIN3iU0NkWG1CSvrq7fTRvIv48CnvYCWqQOGQbhfNk6yZafAc820Sj3kBb6MI0JwG8VR0ufMXRFMknEbcUh+tEDdTzANLYWs7KhgrnzXW98DWJF9hsPtvb5i//AHdR6AImnslsAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/75156fc958ce07e15cdb83a119fce0fb/ca1dc/1.png&apos; srcset=&apos;/static/75156fc958ce07e15cdb83a119fce0fb/e7570/1.png 170w,
/static/75156fc958ce07e15cdb83a119fce0fb/f46e7/1.png 340w,
/static/75156fc958ce07e15cdb83a119fce0fb/ca1dc/1.png 680w,
/static/75156fc958ce07e15cdb83a119fce0fb/02d09/1.png 1020w,
/static/75156fc958ce07e15cdb83a119fce0fb/bbbf7/1.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;유저 프로그램(User Program) : 사용자가 작성한 응용 소프트웨어입니다. 운영체제 위에서 실행되며, 사용자의 요구에 따라 특정 작업을 수행합니다. 예를 들면 워드 프로세서, 웹 브라우저, 게임 등이 있습니다.&lt;/li&gt;
&lt;li&gt;GUI(Graphical User Interface) : 그래픽 기반의 사용자 인터페이스를 제공하는 운영체제의 구성 요소입니다. 유저가 마우스, 키보드 등을 사용하여 그래픽 환경에서 응용 프로그램을 조작하고 상호 작용할 수 있도록 합니다. 이를 통해 사용자는 유저 프로그램과 운영체제의 다른 요소들을 직관적이고 편리하게 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;시스템 콜(System Call) : 유저 프로그램이 운영체제의 기능을 사용할 수 있도록 하는 인터페이스입니다. 유저 프로그램은 시스템 콜을 호출하여 운영체제에게 특정 작업을 요청하고, 운영체제는 해당 요청을 처리합니다. 예를 들면 파일 입출력, 메모리 할당, 프로세스 생성 등의 작업을 시스템 콜을 통해 수행할 수 있습니다.&lt;/li&gt;
&lt;li&gt;커널(Kernel) : 운영체제의 핵심 부분으로, 가장 중요한 기능을 담당합니다. 커널은 시스템 콜을 처리하고, 프로세스 스케줄링, 메모리 관리, 파일 시스템, 네트워킹 등의 핵심 기능을 수행합니다. 일반적으로 커널은 운영체제의 가장 중요한 부분으로서 메모리 상에 상주하여 실행됩니다.&lt;/li&gt;
&lt;li&gt;드라이버(Driver) : 운영체제와 하드웨어 간의 통신을 담당하는 소프트웨어입니다. 각 하드웨어 장치는 운영체제에서 인식하고 제어하기 위해 해당 장치에 대한 드라이버가 필요합니다. 드라이버는 특정 하드웨어와 통신하여 하드웨어의 기능을 사용하고, 운영체제에 필요한 데이터를 전달합니다.&lt;/li&gt;
&lt;li&gt;하드웨어(Hardware) : 컴퓨터 시스템의 물리적인 구성 요소입니다. 이는 CPU, 메모리, 저장 장치, 입출력 장치 등 컴퓨터의 실제 기기를 포함합니다. 운영체제는 하드웨어와 상호 작용하여 자원을 관리하고 사용자 요청을 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이러한 요소들은 운영체제의 구조에서 상호 작용하여, 사용자는 GUI를 통해 유저 프로그램을 실행하고, 유저 프로그램은 시스템 콜을 호출하여 커널의 기능을 사용합니다.&lt;/p&gt;
&lt;p&gt;커널은 드라이버를 통해 하드웨어와 통신하여 자원을 관리하고, 하드웨어는 운영체제와 상호 작용하여 명령을 수행합니다. 이렇게 함께 동작함으로써 운영체제는 컴퓨터 시스템을 효율적으로 제어하고 사용자에게 필요한 서비스를 제공합니다.&lt;/p&gt;
&lt;h3&gt;시스템 콜(System Call)&lt;/h3&gt;
&lt;p&gt;시스템 콜은 유저 모드에서 커널 모드로 전환되어 운영체제의 특권 명령을 실행하고, 그 결과를 유저 프로그램에게 반환합니다.&lt;/p&gt;
&lt;p&gt;시스템 콜의 동작 과정을 자세히 알아 보겠습니다.&lt;/p&gt;
&lt;ol&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&gt;reference : &lt;a href=&quot;https://fjvbn2003.tistory.com/306&quot;&gt;https://fjvbn2003.tistory.com/306&lt;/a&gt; ,
&lt;a href=&quot;https://career-gogimandu.tistory.com/58&quot;&gt;https://career-gogimandu.tistory.com/58&lt;/a&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[PDU (Protocol Data Unit)]]></title><description><![CDATA[PDU의 의미 네트워크의 계층에서 계층으로 데이터를 전달할 때 한 덩어리의 단위를 PDU라고 합니다. PDU는 제어 관련 정보들이 포함된 헤더와 데이터를 의미하는 페이로드로 구성되어 있습니다.  위 그림처럼 PDU…]]></description><link>https://hoonblog.netlify.app/protocol-data-unit/</link><guid isPermaLink="false">https://hoonblog.netlify.app/protocol-data-unit/</guid><pubDate>Mon, 10 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;PDU의 의미&lt;/h2&gt;
&lt;p&gt;네트워크의 계층에서 계층으로 데이터를 전달할 때 한 덩어리의 단위를 PDU라고 합니다. PDU는 제어 관련 정보들이 포함된 헤더와 데이터를 의미하는 페이로드로 구성되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ae9d02439c306ea9b22e5dc9e6d4f5c7/e26aa/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 82.94117647058825%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAABYlAAAWJQFJUiTwAAADc0lEQVR42q2T709bVRjHG/UPci5qcIhzMfOdia8WTURh62QIc3H6D7iYMYfAGGFSKBgnApZRSgtoKYVCe9tSpHQD+VVgpaMtLWuBre0KhY+ntxciyktP8uR57nm+93O+595zVJwwDg4O2N/fl/NJY3d3l2w2e2JPdVjkAE6nE7vdjs83TXt7O5FI5GiBQ3gmk8Fqtcq6w95/gLnJvb0s8XicWCxGMpkUsLDIqaMXcgtmhWZvd490Ok06lZKfc/FPqAxci+7QJQUwejfom4rQOxnCNL2Bzr2OZykqC2ceP0XnDGLwrGMQ/Vz0irrbFWQ+GFfcKsDF9W3qzAFapU20UpQWRxStiAZrCMuj/Lal+Sj1lqA83+KICd0mLfYN7g4/YdIfOw5cCm3TaAlQ3T3BzQ4HVV0St3VuGocDjM7mHboWojSNhrjT5+NWl4uqTomGgb/Q2EJMLf8L6A9tcW94mXqjlxq9hzqDV67vDa8IYFgWuxciaEYDNA7OUtMzIaB2Uc/QbFsTwOjRD8pvOfScWssmbRNpWt1ptK6UyCnuju5gmcl/H2kxwR1rXPSSQpeizfNC1M+pH0kwubx13OFG0IPH9CHu/o8Y11/AYbiA0/gx3oEPWJxulcVLsyac/cWMGcsY6lFjfqBm3FSGa+BTVhasCnA/D3wWNJIyqYjqX+KRVoWvWcVqxytk+lUkvF+SOxSJmSpeCE24+2Xm2lRMa/J1ZkBFfL5JuRFZBbjm49mDcnb0lTz+uZTA/YvEdBXs9V4h7tHlgQ8HSfd8TrKvkuWfign+UkLKeJW0voz4nE0BKg7D/kUkTTX25lp6bn9Lb/UNhhq/x9NSzZzNImsX3RLjTbXYtQ38evMGnbe+w97agF1Ti9/75/GfMjYd5o3LZt77aozz18c5/7WI62OcVluo6ZyVxW0DS7xaYuKdCjPnrlo4W2mm6IvfOXVxkO6RVVmT3VeAdl+EM+UjvP+Nk6IrJgpKOmRwQfkYdb/NyeL7f6zyZqmet4t/5MwnGgqLmyn6rIUCtRG9LaBcz0OH3jCvq4d499o4RRVWsbKFc9dsvKa28kOH4tC0xKlSM4VqA28JSMElA4WX+zh9yYLOunLc4eZWCtvUunAalt3mwvEwzKiY8wcTstj/JEG/Y40hTwjzxLqIfO6X1giEt4+fw/9z/A0IXIJ+LNkyLgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;각 계층의 PDU&apos; title=&apos;&apos; src=&apos;/static/ae9d02439c306ea9b22e5dc9e6d4f5c7/ca1dc/1.png&apos; srcset=&apos;/static/ae9d02439c306ea9b22e5dc9e6d4f5c7/e7570/1.png 170w,
/static/ae9d02439c306ea9b22e5dc9e6d4f5c7/f46e7/1.png 340w,
/static/ae9d02439c306ea9b22e5dc9e6d4f5c7/ca1dc/1.png 680w,
/static/ae9d02439c306ea9b22e5dc9e6d4f5c7/e26aa/1.png 1016w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;각 계층의 PDU&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;위 그림처럼 PDU는 각 계층마다 부르는 이름이 다릅니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;애플리케이션계층 : 메시지&lt;/li&gt;
&lt;li&gt;전송계층 : 세그먼트(TCP), 데이터그램(UDP)&lt;/li&gt;
&lt;li&gt;인터넷계층 : 패킷&lt;/li&gt;
&lt;li&gt;링크계층 : 프레임(데이터링크계층),비트(물리계층)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PDU 중 아래 계층인 bit로 송수신하는 것이 모든 PDU 중 가장 빠르고 효율성이 높습니다. 하지만 애플리케이션계층에서는 문자열을 기반으로 송수신을 하는데, 그 이유는 헤더에 authorization값 등 다른 값들을 넣는 확장이 쉽기 때문입니다.&lt;/p&gt;
&lt;h3&gt;헤더&lt;/h3&gt;
&lt;p&gt;헤더란? 저장되거나 전송되는 데이터 블록의 맨 앞에 위치한 보충 데이터를 말합니다. 데이터 전송에서 헤더를 따르는 데이터는 페이로드(payload), 바디(body)로 불리기도 합니다.&lt;/p&gt;
&lt;p&gt;예를 들어 e-mail을 보낼 때 텍스트(바디)는 보내는 사람, 받는 사람, 제목, 보내는 시간표, 받는 시간표, 마지막 메일 전송 에이전트 등이 전제되어야 합니다.&lt;/p&gt;
&lt;p&gt;헤더 구성은 구문 분석을 위하여 뚜렷하고 모호하지 않은 규격이나 포맷을 따라야 합니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[TCP/IP 4계층 모델]]></title><description><![CDATA[들어가며 인터넷 프로토콜 스위트는 인터넷에서 컴퓨터들이 서로 정보를 주고받는 데 사용하는 프로토콜의 집합이다. 이를 TCP/IP 4 계층 모델로 설명하거나 OSI 7 계층 모델로 주로 설명하는 경우가 많습니다. 여기서 TCP/IP…]]></description><link>https://hoonblog.netlify.app/tcp-ip-4/</link><guid isPermaLink="false">https://hoonblog.netlify.app/tcp-ip-4/</guid><pubDate>Sun, 09 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;들어가며&lt;/h2&gt;
&lt;p&gt;인터넷 프로토콜 스위트는 인터넷에서 컴퓨터들이 서로 정보를 주고받는 데 사용하는 프로토콜의 집합이다. 이를 TCP/IP 4 계층 모델로 설명하거나 OSI 7 계층 모델로 주로 설명하는 경우가 많습니다. 여기서 TCP/IP 4 계층 모델은 OSI 7 계층과는 다르게 통신 프로토콜의 집합으로 계층들은 프로토콜의 네트워킹 범위에 따라 4개의 추상화 계층으로 구성되어 있습니다.&lt;/p&gt;
&lt;h2&gt;TCP/IP 계층과 OSI 7계층 비교&lt;/h2&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0562c747a10b896ef51cfe860462807e/42a19/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 64.11764705882354%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAACMElEQVR42qWRzW8SQRjG919pooeSKJo0JiStFz3of2B6sTEejLapMbaJ3jTxIKVA8SNEubRJD6hboNRdwC1Ru2FZvloUUpa0fCwL5WPpgnZ3aQq7DjtI8Ox7eud95vfMzDOIqpWiqmfdrihKx0JLkmVF/afAUpSkE1FsHgty53Q4R4bdaadTzOcSMbrMlfqAooywKscW8gfZCEU26rWhisA99ZZEZurfU1xov0ru19KsACFoAJbUgRDNtRLF36FssypIUEV6Gp1ihWcf9hbsvkW77+ka5Qyxmr0KrVGaW8JyK/6c1XdowvM/iwJUEXgBpty2elNWz67ZFTOi8a14ZRT2JWsm167RGVpG6bfEIVNpD2B4cpptWwPVF87E83V66XMRjdRHYXectwUbjh3+/U7TFuTTpV/Dk3uga3LbDD4R3TCEPxlS3kuFyCMtqZ6qqYXoYzCMbFxNeKYy2GWeDWhwD1GVLugkNnDmOc+u6hjH+MnHsQ51X/kLg0YOz8noWNYxXlzTdT3npAIOrQdvLmeZb3ab22xEl18Sr817mBf+B1ST+Nb2G4vbYsJeWcA2LpOBKtLrW6vBxNHkbPDag83rs5uGeyDzJBiCOKD65N2PyXny5sLXG4vk1DxJRPtxAgnparI/XNLfxvXT6xdvreqm3XOW6Cj8cCV2YYaYmHFduYvp7xA4VRrAMM8jXvTRlQDN+qkCTnFxpjmadpzhMYojYvUvsSpQKw1xkLb6H/UHZmuYIZ9B2hAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/0562c747a10b896ef51cfe860462807e/ca1dc/1.png&apos; srcset=&apos;/static/0562c747a10b896ef51cfe860462807e/e7570/1.png 170w,
/static/0562c747a10b896ef51cfe860462807e/f46e7/1.png 340w,
/static/0562c747a10b896ef51cfe860462807e/ca1dc/1.png 680w,
/static/0562c747a10b896ef51cfe860462807e/02d09/1.png 1020w,
/static/0562c747a10b896ef51cfe860462807e/42a19/1.png 1024w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;위 그림을 확인해보면 OSI 계층과 TCP/IP 계층의 다른 점을 몇 가지 확인할 수 있다. 첫 번째는 OSI 계층은 TCP/IP 계층의 애플리케이션계층을 3개로 나누고 있고, 두번째는 링크 계층을 데이터 링크 계층과 물리 계층으로 나누고 있다. 세번쨰는 네트워크 계층을 인터넷 계층으로 부르고 있다는 점입니다.&lt;/p&gt;
&lt;h2&gt;Application 계층&lt;/h2&gt;
&lt;p&gt;애플리케이션계층은 FTP, HTTP, SSH, SMTP, DNS 등 응용프로그램이 사용되는 프로토콜 계층이며 웹서비스나 이메일등 서비스를 실질적으로 사람들에게 제공하는 계층입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FTP : 파일 전송 프로토콜(File Transfer Protocol)의 약자입니다. 그 의미를 자세히 살펴보면 기본적으로 &apos;프로토콜&apos; 또는 인터넷 프로토콜은 전자기기가 서로 통신하는 데 필요한 절차나 규칙을 말합니다. &lt;strong&gt;&lt;em&gt;FTP는 TCP/IP 네트워크상의 장치가 파일을 전송할 때 사용하는 프로토콜입니다.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;SSH : 네트워크 상 다른 컴퓨터의 쉘을 사용할 수 있게 해 주는 프로그램 혹은 그 프로토콜을 의미합니다. SSH를 사용하면 원격에서 네트워크 상의 컴퓨터에 접속할 수 있습니다. 쉽게 말해 &lt;strong&gt;&lt;em&gt;보안되지 않은 네트워크 서비스를 안전하게 운영하기 위한 암호화 네트워크 프로토콜입니다.&lt;/em&gt;&lt;/strong&gt; 교환된 대칭 키를 이용해 SSH 서버와 클라이언트 간 모든 통신은 암호화하여 진행되기 때문에, SSH 연결은 매우 안전합니다.&lt;/li&gt;
&lt;li&gt;HTTP : HTML 문서와 같은 리소스들을 가져올 수 있도록 해주는 프로토콜입니다. &lt;strong&gt;&lt;em&gt;HTTP는 웹에서 이루어지는 모든 데이터 교환의 기초이며, 클라이언트-서버 프로토콜이기도 합니다.&lt;/em&gt;&lt;/strong&gt; 클라이언트-서버 프로토콜이란 (보통 웹브라우저인) 수신자 측에 의해 요청이 초기화되는 프로토콜을 의미합니다. &lt;/li&gt;
&lt;li&gt;SMTP : &lt;strong&gt;&lt;em&gt;전자 메일 전송을 위한 인터넷 표준 통신 프로토콜 입니다.&lt;/em&gt;&lt;/strong&gt; 한 메일서버에서 다른 메일서버로 메일을 전송할 때, 송신자의 user agent에서 본인의 메일서버로 메일을 전송할때 SMTP가 사용됩니다. 참고로 SMTP는 HTTP보다 훨씬 더 오래전부터 사용되고 있습니다.&lt;/li&gt;
&lt;li&gt;DNS : 전 세계에 배포된 서비스로  www.naver.com 같이 사람이 읽을 수 있는 이름을 192.0.2.1과 같은 숫자 IP 주소로 변환하여 컴퓨터가 서로 통신할 수 있도록 합니다. &lt;strong&gt;&lt;em&gt;인터넷의 DNS 시스템은 이름과 숫자 간의 매핑을 관리하여 마치 전화번호부와 같은 기능을 합니다.&lt;/em&gt;&lt;/strong&gt; DNS 서버는 이름을 IP 주소로 변환하여 도메인 이름을 웹 브라우저에 입력할 때 최종 사용자를 어떤 서버에 연결할 것인지를 제어합니다. 이 요청을 쿼리라고 부릅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Transport 계층&lt;/h2&gt;
&lt;p&gt;전송계층은 송신자와 수신자를 연결하는 통신 서비스를 제공하고, 연결 지향 데이터 스트림 지원, 신뢰성, 흐름제어를 제공할 수 있으며 애플리케이션 계층과 인터넷 계층 사이에 데이터를 전달할 때 중계 역할을 하는 계층입니다. 대표적으로 TCP와 UDP가 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TCP : Transmission Control Protocol의 약자로 패킷 사이의 순서를 보장하고 연결지향 프로토콜을 사용해서 연결하여 신뢰성을 구축하여 수신 여부를 확인가능하며 &lt;strong&gt;&lt;em&gt;가상 회선 패킷 교환 방식&lt;/em&gt;&lt;/strong&gt;을 사용합니다.&lt;/li&gt;
&lt;li&gt;UDP : User Datagram Protocol의 약자로 패킷 사이의 순서를 보장하지 않고 수신 여부를 확인하지 않으며 단순히 데이터만 주는 &lt;strong&gt;&lt;em&gt;데이터그램 교환 방식&lt;/em&gt;&lt;/strong&gt;을 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;가상 회선 패킷 교환 방식 VS 데이터그램 교환 방식&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;가상 회선 패킷 교환 방식 : 데이터를 전송하기 전에 논리적 연결을 설정하게 된다. 이를 가상회선이라 칭한다. 각각의 패킷에는 가상 회선 식별 번호(VCI)가 포함되어 있고, 모든 패킷들을 전송하면 가상회선이 해제되며 패킷들은 전송한 순서대로 도착합니다. (연결 지향)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/06453efad3307235b3876e639d4e370d/9d517/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 78.23529411764706%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAACSklEQVR42p1U2ZLTMBDM/38JvMMfULzzEhKWTZz4tmzLt3zIbnrszRK2shSFqqZGkqVxT0+PdngzFvz7WB6c390m1lqk7YBmtOt6HEcMNMwWE33XNJgGfq9rjPTvjV3Pj6Hv4+hH+PiU4ss1Q5xr7L2IezEONCdKcLh42LsRnDDGKVLwU42wNrjqGo7rYZqmLaAgUUpBFyXhL7BENNoZTWfQmR5l3aBpO9Rcl/R2XjDRxsli4LmKe3GSoO/7P1O+H/M8Y1kW+gXGbhRYQcA98fPL3sOUBWGe5yjITSmIyJWjMuyZ6jcvwYdDDFflcP0A1zCCG4QIJaOyekFtkJEiAfEa0PNcXGOFxEzI2h6qbhFmer3kMbjw5XF9UtyTAF2PrOmQ9RPcosazc4Hpui2gpCYm6fzveI0hAQWqVGjljSbykXljNhT7pIRmYQqtcSZClWardOTcsty4nn8H3FL2cIkTBJVBoMuVswNl85Py+HoO8YPzJy/E56OHc5zCJQV+miNu+lU2kvJNmzv5U1mWqFkMy5+wsKtfUY8DD/bo6Q0vyN6tO2ZBRj8MIyVX/F02D0hi5wxraiMv3i5boWa0j2WjK/LE6uX0eVXjxNSOocKFVY7I24ndcPJDeJTNd1Kg2AhO3uDTcwZF2eCew4Ct5yYp0sFCm4HFMFBlzW7pEPBwUlSIaH7RoB4mlDT5ueb5qGpxvlzRte0b2dy9G8JrUWgEgQ9N9Ekc0WdIomhd3/r2oWwePUfyUV6ajgjFG2M2I3cDi7MGeOf5+gXZyNhidpNxlgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://woovictory.github.io/2018/12/28/Network-Packet-Switching-Method/&apos; title=&apos;&apos; src=&apos;/static/06453efad3307235b3876e639d4e370d/ca1dc/2.png&apos; srcset=&apos;/static/06453efad3307235b3876e639d4e370d/e7570/2.png 170w,
/static/06453efad3307235b3876e639d4e370d/f46e7/2.png 340w,
/static/06453efad3307235b3876e639d4e370d/ca1dc/2.png 680w,
/static/06453efad3307235b3876e639d4e370d/9d517/2.png 910w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://woovictory.github.io/2018/12/28/Network-Packet-Switching-Method/&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;데이터그램 교환 방식 : 데이터를 전송하기 전 논리적 연결을 설정하지 않고, 패킷들이 독립적으로 전송된다. 이를 데이터그램이라 칭한다. 패킷을 수신한 라우터는 최적의 경로를 선택하여 패킷을 전송하는데, 하나의 매시지에서 분할되어 있는 여러 개의 패킷은 서로 다른 경로로 전송될 수 도 있습니다. (비연결 지향형)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c86f999cf87c4493cd90a9e08daa30c1/f101e/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 77.05882352941177%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB3ElEQVR42pWTW4vbQAyF/f//VPtU6EsLfVjYUkIITuL7/W4nZ+eT1yYtadkOCI81I+mcI42n93W/3zXPE5v9H7vdbmbjOJpN06Su6+zs2fKWZVFRFMryXJ+PiT6dcrV1pbIslSSJqqpSlmWK40RRFJmPLzF931uxpmnMLCGO6/Wqy+Wim6s6LSuaumlVuaQkzF0xAkgCunmed7TEh2Fo8aD2Hun9az3eeXZ38xlCoFNxQS8kcOgOMdRrjX2ntm2N9mZQxgdS4kHK3hKyOZ/P8n3fnMMwKHfUfpwCfT0G+n4KlUWhojjetUMGjKT0YJPMEgIVhGjzGwVXeZhm9c5AzT2C8esPyoDYOu99RDfCodX0g4LCNalu/hpjY7NpA2XQluU6NvigliSp0jjSt4OvL7986ypnUKbQJsPeFLRBh22QaRBjUrumYIwNwYULesl6TfOixRUHAOyZ0SAI/n9sPnLurU9u3p8YEmD4EBoJVhlKs2MQ6xpGxsJ1SD+TWoeiJ6VpbRrSciizp2NogkF11TBRmqbKs1Qvl0Rhmtsrap0sUTvq1Q8Uu9HaERJE9W2BlH+SxG7+aALJSdw1taF7lKBr12dJ3NOxoXMk2IyEBFAgjGIrBhvT7t22sXkDyfCN7vz+vAkAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://woovictory.github.io/2018/12/28/Network-Packet-Switching-Method/&apos; title=&apos;&apos; src=&apos;/static/c86f999cf87c4493cd90a9e08daa30c1/ca1dc/3.png&apos; srcset=&apos;/static/c86f999cf87c4493cd90a9e08daa30c1/e7570/3.png 170w,
/static/c86f999cf87c4493cd90a9e08daa30c1/f46e7/3.png 340w,
/static/c86f999cf87c4493cd90a9e08daa30c1/ca1dc/3.png 680w,
/static/c86f999cf87c4493cd90a9e08daa30c1/f101e/3.png 870w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://woovictory.github.io/2018/12/28/Network-Packet-Switching-Method/&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h4&gt;차이점&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;데이터 그램은 패킷마다 라우터가 경로를 선택하지만, 가상회선 방식은 경로를 설정할 때 한 번만 수행한다.&lt;/li&gt;
&lt;li&gt;정해진 시간 안이나 다량의 데이터를 연속으로 보낼 때는 가상 회선 방식이 적합하지만, 짧은 메시지의 일시적인 전송에는 데이터그램 방식이 적합하다.&lt;/li&gt;
&lt;li&gt;네트워크 내에 한 노드가 다운되면 데이터그램 방식은 다른 경로를 새로 찾아서 설정하지만, 가상 회선 패킷 교환 방식은 다운된 노드를 지나는 모든 가상 회선을 잃게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Internet 계층&lt;/h2&gt;
&lt;p&gt;인터넷 계층은 장치로부터 받은 네트워크 패킷을 IP 주소로 지정된 목적지로 전송하기 위해 사용되는 계층입니다. IP, ARP, ICMP 등이 있고, 패킷을 수신해야 할 상대의 주소를 지정하여 데이터를 전달합니다. 상대가 제대로 받았는지에 대해 보장하지 않는 비연결형적인 특징을 가지고 있습니다.&lt;/p&gt;
&lt;h2&gt;Link 계층&lt;/h2&gt;
&lt;p&gt;링크 계층은 전선이나 광섬유, 무선 등을 이용하여 실질적인 데이터를 전달하며 장치 간 신호를 주고받는 규칙을 정하는 계층입니다. 다른 말로는 네트워크 접근 계층이라고 부르기도 합니다.&lt;/p&gt;
&lt;p&gt;링크 계층을 물리계층과 데이터 링크 계층으로 나누기도 하는데 &lt;strong&gt;&lt;em&gt;물리계층은 무선 LAN과 유선 LAN을 통해 0과 1 로이루어진 데이터를 보내는 계층&lt;/em&gt;&lt;/strong&gt;을 말하며, &lt;strong&gt;&lt;em&gt;데이터 링크 계층은 &apos;이더넷 프레임&apos;을 통해 에러 확인, 흐름제어, 접근제어를 당당하는 계층&lt;/em&gt;&lt;/strong&gt;을 말합니다.&lt;/p&gt;
&lt;p&gt;유선 LAN을 이루는 이더넷은 IEEE802.3이라는 프로토콜을 따르며, 양쪽의 장치가 동시에 송수신할 수 있는  방식인 전이중화(full duplex) 통신을 사용합니다. 전이중화 방식은 송신로와 수신로를 나누어 같은 시간에 데이터를 주고받을 수 있습니다. 현대의 고속 이더넷은 전이중화 방식을 기반으로 통신하고 있습니다.&lt;/p&gt;
&lt;p&gt;유선 LAN은 과거 &lt;strong&gt;&lt;em&gt;CDMA/CD&lt;/em&gt;&lt;/strong&gt; 방식을 사용했었다. 이 방식은 데이터를 보낸 후 충돌이 발생할 시 일정시간 이후에 재전송하는 방식을 말합니다. 전이중화 방식과는 다르게 한경로를 송신과 수신을 함께 보내는 방식이어서 데이터 충돌에 대비해야 했습니다.&lt;/p&gt;
&lt;h3&gt;광섬유 케이블&lt;/h3&gt;
&lt;p&gt;광섬유 케이블은 말 그대로 광섬유를 사용하여 만든 케이블을 말합니다. 빛을 이용하여 통신하기 때문에 과거에 사용했던 동축 케이블이나 구리선과는 비교할 수 없을 만큼의 장거리 통신이나 고속의 통신이 가능합니다. 보통 100 Gbps 속도를 내며, 밑의 그림에서 처럼 광섬유 내에서 빛이 반사하면서 반대편 끝까지 가는 원리입니다. 굴절률이 높은 부분을 코어, 낮은 부분을 클래딩이라고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 588px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7bccfedb5dd350f9b7b1daed1bce9493/f81fd/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 59.411764705882355%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsTAAALEwEAmpwYAAABoUlEQVR42o1SyW4UMRD1iV/lB8JXIC6IO5fc4IREjgPhGAkEShAoIxjN0jPdbbftbi/trVx4psMomXCgZJWsWvxePRfB/zYASJBDysr4GFOJkMdFOR8vOSYIMWnjpXJdP3ZS1w1nXPF+BMjkXwh50L7XnvW+k7bhmgkt26anjW6rsL4ZV9c1U85HsgeaDt4h8sHdztfVcjPQnXExWhWqHxkKXYpxBLZAWe0aXsiTU8YZqs3WcNpylepbtCKLdbYytb9AVCGjj6Csa7viAinRuLnxPy+BrUp7qufV9y/m97e22hSFvKRWMi24pC2VYyd0wxQTZjBuPzMYnpp5oos8DnvwoRa837bdYrmttw2lnElHuS4S6GE3uiIfHEW9T7sE0kEv7MWubulgkwsphHiXj6JkS03Oaap8JNj0Zhoy+NNviPIo6mTkL2axGvEj4gfEFUaD4E6bg0K8du6F1q9CeI44m5rTwb++uiKXn4j3z7AsENiHE+2XC/PL9xfk/PzJbEYAnk7NcPCfrT1T6iyliwMVOFm8g19q/da5d8a8Qfz6BzFprNpzCYJuAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;광섬유 내부에서의 빛의 이동&apos; title=&apos;&apos; src=&apos;/static/7bccfedb5dd350f9b7b1daed1bce9493/f81fd/4.png&apos; srcset=&apos;/static/7bccfedb5dd350f9b7b1daed1bce9493/e7570/4.png 170w,
/static/7bccfedb5dd350f9b7b1daed1bce9493/f46e7/4.png 340w,
/static/7bccfedb5dd350f9b7b1daed1bce9493/f81fd/4.png 588w&apos; sizes=&apos;(max-width: 588px) 100vw, 588px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;광섬유 내부에서의 빛의 이동&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Java 조건문]]></title><description><![CDATA[조건문은 말 그대로 주어진 조건식의 결과에 따라 별도의 명령을 수행하도록 제어하는 명령문입니다.
자바에서 사용되는 조건문은 크게 if문과 switch문이 있습니다. if문 if문은 소괄호 안에는 boolean…]]></description><link>https://hoonblog.netlify.app/java-conditional/</link><guid isPermaLink="false">https://hoonblog.netlify.app/java-conditional/</guid><pubDate>Sat, 08 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;조건문은 말 그대로 주어진 조건식의 결과에 따라 별도의 명령을 수행하도록 제어하는 명령문입니다.
자바에서 사용되는 조건문은 크게 &lt;strong&gt;&lt;em&gt;if문&lt;/em&gt;&lt;/strong&gt;과 &lt;strong&gt;&lt;em&gt;switch문&lt;/em&gt;&lt;/strong&gt;이 있습니다.&lt;/p&gt;
&lt;h2&gt;if문&lt;/h2&gt;
&lt;p&gt;if문은 소괄호 안에는 boolean 값으로 평가될 수 있는 조건식을 넣어주고, 중괄호 안의 실행 블록에는 조건식이 참일 때 실행하고자 하는 코드를 적어주면 된다. 소괄호 안에 조건문이 참(true) 일 때만 주어진 명령문이 실행된다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;참고로 else문은 생략이 가능하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; ifexam &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; num1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; num2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; num3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num1 &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; num3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//if문의 조건식이 참이어서 실행&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;num1과 num3은 같습니다.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num1 &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; num2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// if문은 거짓이기 때문에 else문이 바로 실행 되어 &quot;다릅니다.&quot; 출력&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;같습니다.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//else는 if문이 거짓일때 실행&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;다릅니다.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num1 &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; num3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//if문은 거짓, else if문은 참이기 때문에 &quot;num2가 num3보다 작습니다.&quot; 출력&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;num1이 num3보다 큽니다.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num2 &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; num3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//else if는 if문이 거짓이고, else if문의 조건식이 참 일경우 실행&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;num2가 num3보다 작습니다.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/89cb5f9bc8e42cfba2e03d19b0436824/bbbf7/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.470588235294116%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB3UlEQVR42o2Sy27TQBSG867wAPACIFiwY1N2wAaqSkiFDUSoQl20otAgEqpESUoS0sRObBLnanvqy/jyMXZIFCCVONansTRn/vPPnFOAFIhZrev/3ZFE10ihKzQS6ezMKeSJSieNJUkS5ZI7xdSe6O4xr9xmWr6F236EDOx8L82/34JRuMTTnjFvPGDRfIhnvCFN05xkizzCCbFdRy5qEIyUUrrJXVNIIg9pHeFrLwn0feTs840uLWfMWeeYk9YRxmKAcAXVrsXH+khhUm5bFLLDQkraZhNt2sOPUyIZYUwcvg/mtBS9n8vMDJY95NNlkQ+VVwxnXeI4ptGfclY3FEMuOkowSRLq2jmHpSe8qzynP74k8APKrRHFLz2KpStOa8bm2nNh0Tc7qkBCqIwMJy66JdDGLsZUrJqSheOYTCx9cz0viHA8iasQfpQPwA+zymtV+LC0R0MvsbRdjr/pqmiPt+ddTqpDCtKf4V89ZlK5y+ziDp7+In/cm8J2lcNBS3V9lbMUAQtXIULs61BdOQ4J51/xzCL+6D2h3dwc3nQvm071Xv5gn2X9PvPaPdXEp0Shu878cw7/JzLhcFZCaAcI/UBN0CmZmX8GO6scR3KLKHezE2Vkm6yhf+f8AisgQuHdYLlpAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;if문의 순서도&apos; title=&apos;&apos; src=&apos;/static/89cb5f9bc8e42cfba2e03d19b0436824/ca1dc/1.png&apos; srcset=&apos;/static/89cb5f9bc8e42cfba2e03d19b0436824/e7570/1.png 170w,
/static/89cb5f9bc8e42cfba2e03d19b0436824/f46e7/1.png 340w,
/static/89cb5f9bc8e42cfba2e03d19b0436824/ca1dc/1.png 680w,
/static/89cb5f9bc8e42cfba2e03d19b0436824/02d09/1.png 1020w,
/static/89cb5f9bc8e42cfba2e03d19b0436824/bbbf7/1.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;if문의 순서도&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h2&gt;switch 문&lt;/h2&gt;
&lt;p&gt;switch문은 if문과 같은 조건문이지만, 변수가 어떤 값을 갖느냐에 따라 실행문이 선택됩니다. switch 문은 if /else 문보다 가독성이 더 좋으며, 컴파일러가 최적화를 쉽게 할 수 있어 속도 또한 빠른 편입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Scanner&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; switchExam &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Scanner&lt;/span&gt; num &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Scanner&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;in&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; dice &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; num&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;nextLine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//주사위 번호를 입력한다.&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dice&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1칸 이동&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//break는 다음 case를 실행하지 않고, switch문 탈출할 수 있습니다.&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2칸 이동&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;3&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;3칸 이동&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;4&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;4칸 이동&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;5칸 이동&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;6&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;6칸 이동&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//switch문의 괄호 안 값과 같은 값이 없으면, 여기서 실행문을 실행합니다.&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;없는 숫자입니다! &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; dice&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Scanner를 이용하여 1 ~ 6의 숫자를 입력 받아 각각의 case에서 출력해 주고 종료되고 있습니다. 만약 1 ~ 6이 아닌 숫자를 받을 경우, &quot;없는 숫자입니다.&quot;가 출력되고 종료됩니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[HTTPS에 대한 간단한 정리]]></title><description><![CDATA[HTTPS의 의미 HTTPS의 사전적 의미는 하이퍼텍스트 전송 프로토콜 보안(HTTPS)은 웹 브라우저와 웹 사이트 간에 데이터를 전송하는 데 사용되는 기본 프로토콜인 HTTP의 보안 버전입니다. HTTPS…]]></description><link>https://hoonblog.netlify.app/https/</link><guid isPermaLink="false">https://hoonblog.netlify.app/https/</guid><pubDate>Fri, 07 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6bc453eae40273e429539f346cf307db/f20da/1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 36.47058823529412%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAHABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB1qFB/8QAGBAAAwEBAAAAAAAAAAAAAAAAAAIRAxL/2gAIAQEAAQUC5cmkY//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAEFAQAAAAAAAAAAAAAAABEAAQIQIjL/2gAIAQEABj8CzMLpjX//xAAYEAEBAQEBAAAAAAAAAAAAAAABEQAhMf/aAAgBAQABPyFSMEOTc44CIe83/9oADAMBAAIAAwAAABCAD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABsQAQACAgMAAAAAAAAAAAAAAAERIQAxUWGR/9oACAEBAAE/ELtOyWw5wZm2UIjr2MuxgCXbn//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/6bc453eae40273e429539f346cf307db/f20da/1.jpg&apos; srcset=&apos;/static/6bc453eae40273e429539f346cf307db/0b705/1.jpg 170w,
/static/6bc453eae40273e429539f346cf307db/31389/1.jpg 340w,
/static/6bc453eae40273e429539f346cf307db/f20da/1.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;HTTPS의 의미&lt;/h2&gt;
&lt;p&gt;HTTPS의 사전적 의미는 하이퍼텍스트 전송 프로토콜 보안(HTTPS)은 웹 브라우저와 웹 사이트 간에 데이터를 전송하는 데 사용되는 기본 프로토콜인 HTTP의 보안 버전입니다. HTTPS는 데이터 전송의 보안을 강화하기 위해 암호화됩니다. 이는 사용자가 은행 계좌, 이메일 서비스, 의료 보험 공급자에 로그인하는 등 중요한 데이터를 전송할 때 특히 중요합니다.&lt;/p&gt;
&lt;p&gt;모든 웹 사이트, 특히 로그인 자격 증명이 필요한 웹 사이트는 HTTPS를 사용해야 합니다. 크롬 등 최신 웹 브라우저에서는 HTTPS를 사용하지 않는 웹 사이트가 HTTPS를 사용하는 웹 사이트와 다르게 표시됩니다.&lt;/p&gt;
&lt;h2&gt;HTTPS의 특징&lt;/h2&gt;
&lt;h3&gt;1. 암호화&lt;/h3&gt;
&lt;p&gt;외부인이 서버와 클라이언트가 주고받는 정보를 탈취할 수 없도록 한다. 서버와 클라이언트가 HTTPS를 사용하면 서로 합의한 방식으로 데이터를 암호화하여 주고받는다. 이때 외부인이 데이터 탈취에 성공하더라도 암호화되어 알아볼 수 없게 된다. 하지만 HTTP는 데이터 암호화가 따로 적용되지 않아서 외부인이 데이터 탈취 시에 쉽게 정보를 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;여기서 서버와 클라이언트의 암호화 방식은 대칭키 방식과 비대칭키 방식을 혼용하여 사용한다. 대칭키 방식은 비대칭키 방식 보다 알고리즘이 덜 복잡하여 대칭키를 사용하여 암복호화 하는 편이 컴퓨터에 부담을 덜 줄 수 있기 때문에 서버와 클라이언트가 데이터를 주고 받을 때 사용 합니다. 대칭키 방식은 공통의 비밀키를 공유하여 서로의 데이터를 암호화 복호화할 수 있고, 비대칭키 방식은 각각 공개키와 비밀키(개인키)를 가지고 상대가 나의 공개키로 암호화한 데이터를 개인이 가진 비밀키로 복호화하는 것을 의미합니다.&lt;/p&gt;
&lt;p&gt;여기서 대칭키를 주고 받는 상황에서 데이터 탈취가 일어난다면 암호화를 하게 되더라도 복호화될 가능성이 높습니다. 그래서 HTTPS는 대칭키를 주고 받을때는 비대칭키 방식을 사용하도록 되어 있습니다.&lt;/p&gt;
&lt;h3&gt;2. 인증서&lt;/h3&gt;
&lt;p&gt;HTTPS는 브라우저가 서버의 응답과 함께 전달된 인증서를 확인할 수 있습니다. 인증서는 서버의 신원을 보증하여 접속한 사이트가 가짜 사이트가 아닌 것을 보증합니다. 이때 이를 보증할 수 있는 제삼자를 Certificate Authority, &lt;strong&gt;&lt;em&gt;CA&lt;/em&gt;&lt;/strong&gt;라고 부릅니다.
CA는 인증서를 발급해 주는 엄격하게 공인된 기관들을 말하는데,  이러한 CA들은 서버의 공개키와 정보를 CA의 비밀키로 암호화하여 인증서를 발급합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/bc7509594af1b22e2accd5a7a0a9d740/e4ddf/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 121.76470588235296%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAYCAYAAAD6S912AAAACXBIWXMAAAsTAAALEwEAmpwYAAABsklEQVR42s2UWUsDQRCE93epCfikIKjxCgoi/mLzviH3sbnv+2jzNXRYkpCdxBcHirmY6urq3vVubu/k8+tbXpPvcv+QkLfkhySeXuQx8SyXV3G5uIw5Ixa/Fs9Pp+UnlZJ8oSCZTFZRrQYSBIFUKpWTUC6XxRuNRrqYTCbS7/el1+vJcrmU9Xot5wxvMBhIo9EQiCGBbLFYbDGfz2U2m+nsAlWI3FarJZDbBecAst0gx+Ahs16vi+/7Ok+nUyVOb7zN5XLS6XQ0gDPharVS/3iISsAeGwB7AjkTDodDabfbqgxyu2BNqszh80hCKlsqlVTJeDzeeohKgpiXrJ0IqSzpFjZ9CCmHEBDEUuaeTJw95AGVhqDZbGpR8vm8gj0BXCvtkQrRSdf6jQsjMAvCfRnpIV8KhQlfQGhFsbXtIz2s1WpKao9JGU/pw2KxKNlsVj3lDGuOqVQPUYmPdkj6KA6De8NRQtTwQ2CE0zqGyKJYW0BO/7GmQFHEZtFeyhDQb6TGGt9I22XsKvaIAEm329UZfzAe5WcR7vYaM57atx1umUPY8/CQsaf8/5wI/4L/T/gLz2IkdbS0mhUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;tistory의 인증서&apos; title=&apos;&apos; src=&apos;/static/bc7509594af1b22e2accd5a7a0a9d740/ca1dc/2.png&apos; srcset=&apos;/static/bc7509594af1b22e2accd5a7a0a9d740/e7570/2.png 170w,
/static/bc7509594af1b22e2accd5a7a0a9d740/f46e7/2.png 340w,
/static/bc7509594af1b22e2accd5a7a0a9d740/ca1dc/2.png 680w,
/static/bc7509594af1b22e2accd5a7a0a9d740/02d09/2.png 1020w,
/static/bc7509594af1b22e2accd5a7a0a9d740/e4ddf/2.png 1082w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;tistory의 인증서&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;인증서를 발급한 CA, 서명에 사용한 알고리즘, 서명, tstory 공개키 정보 등이 들어있는 것을 확인할 수 있습니다.
서버가 클라이언트에게 CA에서 발급받은 인증서를 전달하면 클라이언트는 OS 또는 브라우저에 미리 내장되어 있던 CA 리스트를 통해 브라우저에서 인증된 CA에서 발급받은 인증서인지 먼저 확인했을 때  만약 인증된 CA에서 발급한 인증서가 아니라면 화면에 경고창을 보여주고, 반대로 CA에서 발급한 인증서 일시 브라우저에서 제공된 CA 기관의 공대키로 서버 인증서를 복호화합니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Java StringBuilder란?]]></title><description><![CDATA[자바의 문자열은 주로 String을 사용한다. 이 문자열이 1개 이상 있을때, 붙여서 사용하는법에서 가장 간단한 방법은 StringBuilder메서드를 사용하는법이라고 생각한다. 이번엔 StringBuilder…]]></description><link>https://hoonblog.netlify.app/java-stringbuilder/</link><guid isPermaLink="false">https://hoonblog.netlify.app/java-stringbuilder/</guid><pubDate>Wed, 05 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;자바의 문자열은 주로 String을 사용한다. 이 문자열이 1개 이상 있을때, 붙여서 사용하는법에서 가장 간단한 방법은 StringBuilder메서드를 사용하는법이라고 생각한다. 이번엔 StringBuilder의 사용법을 알아보려고 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; result1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;자바스프링 - &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; java &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;자바&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Spring&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;스프링&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; java &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Spring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
result1 &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; java &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Spring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;//자바 스프링&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//자바스프링 - 자바스프링&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠ 이런식으로 String 객체끼리 더하는 방법은 메모리 할당과 해제를 발생시키는데, 덧셈 연산이 많아진다면 성능적으로 좋지 않다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그 이유로는 자바에서 String 객체는 변경 불가능하다. 한 번 생성되면 내용을 바꿀 수 없단 뜻이다. 따라서 하나의 문자열을 다른 문자열과 연결하면 새 문자열이 생성되고, 이전 문자열은 가비지 컬렉터로 들어간다. 문자열을 연결하는 작업은 여러 작업이 발생하고,기존 문자열 값의 길이에 추가된 문자열의 크기를 더한 크기의 새로운 문자열이 생성되는데 이런 작업을 여러번 실행하게 되면 메모리를 많이 잡아먹고,실행시간이 길어진다. 그래서 대안으로 &lt;code class=&quot;language-text&quot;&gt;StringBuilder&lt;/code&gt;를 많이 사용한다.  Stirng은 변경 불가능한 문자열을 생성하지만 &lt;code class=&quot;language-text&quot;&gt;StringBuilder&lt;/code&gt;는 변경 가능한 문자열을 만들어 준다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;StringBuilder&lt;/span&gt; stringBuilder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StringBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
stringBuilder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;자바&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;스프링&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        
&lt;span class=&quot;token comment&quot;&gt;//String str = stringBuilder;&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stringBuilder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// String에 StringBuilder를 그대로 넣을 순 없다. toString()을 붙여서 형변환을 해준다.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 두 출력은 같은 값을 출력한다&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stringBuilder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//자바스프링&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//자바스프링&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;StringBuilder의&lt;/code&gt; 객체를 생성한 후, &lt;code class=&quot;language-text&quot;&gt;append()&lt;/code&gt;의 인자로 연결하고자 하는 문자열을 넣어서 &lt;code class=&quot;language-text&quot;&gt;StringBuilder&lt;/code&gt;의 객체를 통해 호출한다. 출력 시에는 &lt;code class=&quot;language-text&quot;&gt;toString()&lt;/code&gt;을 붙여야 하고, String변수에 넣을 때도 같다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[이터레이터 패턴 (Iterator Pattern)]]></title><description><![CDATA[들어가며 이터레이터 패턴은 이터레이터(Iterator)를 사용하여 컬렉션(Collection…]]></description><link>https://hoonblog.netlify.app/iterator-pattern/</link><guid isPermaLink="false">https://hoonblog.netlify.app/iterator-pattern/</guid><pubDate>Sun, 02 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;들어가며&lt;/h2&gt;
&lt;p&gt;이터레이터 패턴은 이터레이터(Iterator)를 사용하여 컬렉션(Collection)의 요소들에 접근하는 디자인 패턴입니다.
이를 통해 순회할 수 있는 여러 가지 자료형의 구조와는 상관없이 이터레이터라는 하나의 인터페이스로 순회가 가능합니다.&lt;/p&gt;
&lt;h2&gt;이터레이터 패턴 구성 요소&lt;/h2&gt;
&lt;p&gt;이터레이터 패턴은 주로 다음과 같은 구성 요소로 구성됩니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Iterator(반복자): 검색된 요소를 순회하는 역할을 담당합니다. 다음 요소로 이동하거나 현재 요소에 접근하는 방법을 제공합니다.&lt;/li&gt;
&lt;li&gt;ConcreteIterator(구체적인 반복자): Iterator 인터페이스를 구현하여 실제로 모음을 순회하는 로직을 구현합니다.&lt;/li&gt;
&lt;li&gt;Aggregate(집합체): 객체들의 집합체를 인터페이스입니다. 이 인터페이스를 구현하는 컬렉션 클래스는 iterator() 메서드를 제공하여 ConcreteIterator 객체를 생성합니다.&lt;/li&gt;
&lt;li&gt;ConcreteAggregate(구체적인 집적체): Aggregate 인터페이스를 구현하여 실제로 집합을 관리하고 iterator() 메서드를 통해 ConcreteIterator 객체를 생성합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/9aac79113be2e2ed80a1fb8a5ad2429f/bbbf7/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.88235294117647%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAABvklEQVR42nVTaY+CUAzk//8pv3nEiIDiERW88MADUdRVhNlOd9/GmGyTF95L2+l0Wqz89UK63yNxHSROG4nnIp3NkN1uKIsCn/Z8PnG+ZEijJRK7hdNggHS3Q3a9oixLWOF0imAyge84sBsNNGs1TEYjjMdj7KUQ7fF4KBAtDENMJSeUnFa9Dq/dxnq1woDAaSqAErDZbjESgK7vK1CSJFiv11gsFrjJPY4iHOT9JSy63a76IgFhzlxiLpcLgiDA8XiENWGlVgvNZhMNYTiTdgnk93qIpVAubB5hICeE9KUAm80Gw+FQAdgmbSdtk4hViE5sh444jpV2nud/LaqJrxStaZGw7XQ6SqJSqWiry+VSC1ylA+td8JsM4vWb+J+xsGHF4vf7Xd/F7wAtssmyTB2Hw0H14J3gJvHdTDz9bNnkXs2U5/O5Cs3h8Nvv95V+TzRkAQYxgYdGfemn9oxlHO8j2Yzz+fwzZQLR4bouPM/TN3UykyPISqbKArZt6yb4shHMYRy/LKJDISCFdWQPCcQJnk4nZcwhfepGNmbKpgMaY3VtuLS8fB6CFm9/ikkkW3ZRrVZRk5+AbI0M1PMb6sM3D0TUaV0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;inpa.tistory.com/1075&apos; title=&apos;&apos; src=&apos;/static/9aac79113be2e2ed80a1fb8a5ad2429f/ca1dc/1.png&apos; srcset=&apos;/static/9aac79113be2e2ed80a1fb8a5ad2429f/e7570/1.png 170w,
/static/9aac79113be2e2ed80a1fb8a5ad2429f/f46e7/1.png 340w,
/static/9aac79113be2e2ed80a1fb8a5ad2429f/ca1dc/1.png 680w,
/static/9aac79113be2e2ed80a1fb8a5ad2429f/02d09/1.png 1020w,
/static/9aac79113be2e2ed80a1fb8a5ad2429f/bbbf7/1.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;inpa.tistory.com/1075&lt;/figcaption&gt;
  &lt;/figure&gt; &lt;/p&gt;
&lt;h2&gt;Iterator 예제 코드&lt;/h2&gt;
&lt;h3&gt;1. Iterator(반복자)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Aggregate 인터페이스 =&gt; 집합체 객체 (컬렉션)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Aggregate&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Iterator&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2. ConcreteIterator(구체적인 반복자)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ConcreteAggregate 클래스&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ArrayCollection&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Aggregate&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 데이터 집합 (컬렉션)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ArrayCollection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;collection &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;//내부 컬렉션을 인자로 넣어 이터레이터 구현체를 클라이언트에 반환&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Iterator&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ArrayIterator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;3. Aggregate(집합체)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 반복체 객체&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Iterator&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hasNext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;4. ConcreteAggregate(구체적인 집적체)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ConcreteIterator 클래스&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ArrayIterator&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Iterator&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; position&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 커서 (for문의 i 변수 역할)&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// 생성자로 순회할 컬렉션을 받아 필드에 참조 시킴&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ArrayIterator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;collection &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;position &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 순회할 다음 요소가 있는지 true / false&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hasNext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; position &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 다음 요소를 반환하고 커서를 증가시켜 다음 요소를 바라보도록 한다.&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;position&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;&lt;code class=&quot;language-text&quot;&gt;Main&lt;/code&gt;코드&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 클라이언트 코드&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 1. 집합체 생성&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; arr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;ArrayCollection&lt;/span&gt; collection &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ArrayCollection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 2. 집합체에서 이터레이터 객체 반환&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;Iterator&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; iterator &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;token comment&quot;&gt;// 3. 이터레이터 내부 커서를 통해 순회&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;iterator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasNext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; iterator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;element&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;이터레이터 패턴의 장점과 단점&lt;/h2&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;일관된 이터레이터 인터페이스를 사용해 여러 형태의 컬렉션에 대해 동일한 순회 방법을 제공한다.&lt;/li&gt;
&lt;li&gt;컬렉션의 내부 구조 및 순회 방식을 알지 않아도 된다.&lt;/li&gt;
&lt;li&gt;집합체의 구현과 접근하는 처리 부분을 반복자 객체로 분리해 결합도를 줄 일 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;단점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;클래스가 늘어나고 복잡도가 증가한다.&lt;/li&gt;
&lt;li&gt;구현 방법에 따라 캡슐화를 위배할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;마치며&lt;/h2&gt;
&lt;p&gt;컬렉션에 대한 순회 논리를 Iterator에 위임함으로써 코드의 확장성이 증가하고, 새로운 컬렉션을 추가하거나 기존 컬렉션의 내부 구조를 변경해도 클라이언트 코드를 수정할 필요가 없다는 점이 눈에 띄게 좋았다.
이러한 경험을 통해 디자인 패턴이 어떻게 코드의 품질을 향상시키고 유지보수를 용이하게 만드는지에 대해 조금은 더 알게된것 같다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[프록시 서버 (Proxy Server)]]></title><description><![CDATA[…]]></description><link>https://hoonblog.netlify.app/proxy-server/</link><guid isPermaLink="false">https://hoonblog.netlify.app/proxy-server/</guid><pubDate>Sun, 02 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;프록시서버의 의미&lt;/h2&gt;
&lt;p&gt;프록시서버는 서버와 클라이언트 사이에서 클라이언트가 자신을 통해 다른 네트워크서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용프로그램을 말합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/285d8deb8d6867d2b719d35d63368bd5/62aaf/1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 48.8235294117647%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAezNRFH/xAAZEAABBQAAAAAAAAAAAAAAAAABAhIgISL/2gAIAQEAAQUCdsKqH//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABkQAAIDAQAAAAAAAAAAAAAAAAERABIgcf/aAAgBAQAGPwKqPYSs/wD/xAAbEAACAQUAAAAAAAAAAAAAAAAAAREgIUFRcf/aAAgBAQABPyGWCjgZqGK6o//aAAwDAQACAAMAAAAQCC//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAdEAACAgEFAAAAAAAAAAAAAAABEQAhEDFRYXGB/9oACAEBAAE/EO6jT4hTiwK7hIJCJDU5iG2P/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://surfshark.com/ko/blog/proxy-server&apos; title=&apos;&apos; src=&apos;/static/285d8deb8d6867d2b719d35d63368bd5/a22ce/1.jpg&apos; srcset=&apos;/static/285d8deb8d6867d2b719d35d63368bd5/0b705/1.jpg 170w,
/static/285d8deb8d6867d2b719d35d63368bd5/31389/1.jpg 340w,
/static/285d8deb8d6867d2b719d35d63368bd5/a22ce/1.jpg 680w,
/static/285d8deb8d6867d2b719d35d63368bd5/29373/1.jpg 1020w,
/static/285d8deb8d6867d2b719d35d63368bd5/62aaf/1.jpg 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://surfshark.com/ko/blog/proxy-server&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h2&gt;프록시 서버의 동작원리&lt;/h2&gt;
&lt;p&gt;프록시 서버는 사용자를 인터넷에서 분리하는 중간서버 역활을 하기 때문에 프록시 서버가 없다면 트래픽이 직접 웹사이트로 흐르게 되고, 프록시 서버를 사용하면 요청한 웹사이트에 이동전에 트래픽이 프록시로 먼저 이동하게 됩니다. 여기서 웹사이트에서의 모든 응답도 프록시 서버에 먼저 갔다가 사용자에게 전달 됩니다.&lt;/p&gt;
&lt;h3&gt;프록시 서버의 사용&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CloudFlare&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CloudFlare는 전세계적으로 분산된서버가 있고 이를 통해 어떠한시스템의 콘텐츠전달을 빠르게 할 수 있는 CDN 서비스 입니다.
CloudFlare를 사용하여 누릴 수있는 이점으로는 DDOS 공격 방어, HTTPS구축이 있습니다.&lt;/p&gt;
&lt;h2&gt;프록시 서버를 사용하는 이유&lt;/h2&gt;
&lt;h3&gt;1. 익명성 유지&lt;/h3&gt;
&lt;p&gt;프록시 서버를 사용하면 웹 요청을 보낼 때 실제 IP 주소를 숨길 수 있습니다. 이는 개인 정보 보호와 익명성을 유지할 수 있도록 도와줍니다. 특히 공용 Wi-Fi 네트워크나 공공 장소에서 인터넷을 사용할 때 개인 정보를 보호하는 데 도움이 됩니다.&lt;/p&gt;
&lt;h3&gt;2. 지리적 제한 우회&lt;/h3&gt;
&lt;p&gt;일부 웹 사이트나 온라인 서비스는 특정 지역에서만 이용 가능하도록 설정되어 있습니다. 프록시 서버를 사용하면 자신의 위치를 숨기고 다른 지역으로 연결하여 이러한 지리적 제한을 우회할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;3. 캐시와 가속&lt;/h3&gt;
&lt;p&gt;프록시 서버는 인터넷 트래픽을 캐시하여 효율적으로 관리할 수 있습니다. 이는 웹 페이지 로딩 속도를 향상시키고 대역폭 사용을 줄여줍니다. 특히 동일한 내용을 반복해서 요청하는 경우에는 프록시 서버에서 캐시된 데이터를 제공함으로써 웹 페이지의 응답 속도를 크게 개선할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;보안 및 필터링&lt;/h3&gt;
&lt;p&gt;프록시 서버는 웹 트래픽을 모니터링하고 보안 위협이나 악성 소프트웨어를 차단하는 데 도움을 줄 수 있습니다. 특히 기업이나 학교에서는 프록시 서버를 사용하여 내부 네트워크 보안을 강화하고 웹 필터링 정책을 적용하는 경우가 많습니다.&lt;/p&gt;
&lt;h3&gt;콘텐츠 제어&lt;/h3&gt;
&lt;p&gt;프록시 서버를 사용하면 특정 유형의 콘텐츠에 대한 액세스를 제어할 수 있습니다. 예를 들어, 부적절한 콘텐츠를 차단하거나 특정 웹 사이트에 대한 액세스를 제한할 수 있습니다. 이는 가정이나 조직에서 인터넷 사용 정책을 시행하거나 부모가 자녀의 온라인 활동을 관리하는 데 도움이 됩니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[프록시 패턴 (Proxy Pattern)]]></title><description><![CDATA[들어가며 프록시 패턴을 설명하기 전 먼저 프록시의 의미부터 설명하겠습니다.
우리는 소프트웨어 기술에서 종종 '프록시'라는 용어를 듣게 되는데 리버스프록시,프록시서버, lazy…]]></description><link>https://hoonblog.netlify.app/proxy_pattern/</link><guid isPermaLink="false">https://hoonblog.netlify.app/proxy_pattern/</guid><pubDate>Sun, 02 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;들어가며&lt;/h2&gt;
&lt;p&gt;프록시 패턴을 설명하기 전 먼저 프록시의 의미부터 설명하겠습니다.
우리는 소프트웨어 기술에서 종종 &lt;strong&gt;&apos;프록시&apos;라는 용어를 듣게 되는데 리버스프록시,프록시서버, lazy전략에서 사용되는 프록시객체, 프록시패턴 등등 프록시란 &apos;대리&apos;라는 의미로 프록시에게 어떤 일을 대신시키는 것입니다.&lt;/strong&gt;
대신 중요한 건 클라이언트 쪽에서 실제  실행시킬 클래스에 대한객체를 통해 메서드를 호출하고 반환 값을 받는지, 대리자 객체를 통해 메서드를 호출하고 반환 값을 받는지 전혀 모르게 처리한다는 것입니다.
예를 들어 보안분야에서, 보안상의 이유로 서버를 외부에 노출시키지 않기 위해 서버와 클라이언트단 중간에서 접점을 담당하는 서버를 보고 프록시서버라고 부릅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ac9af4748c08e95b3faa431f867fc032/3adb2/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.35294117647059%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAABDElEQVR42kWQ606DQBCF+/IYTRQt0djUNr5DUzFRn6Ex/KECSQnXcunCLvd7D8WkE3bYnZ1vzs7MhmFomsZ1XcMwoijCse/7oiiyLCvLsm3bKQJvWdbud4dv/7efIjP88jxXVVWSJJQIgoAQAs8YJeQUxzGSuq6D/xC3N3ccd8st3hbQG+E0TX3f9zwPsoyxJEkAYBOGIa4QPHpH1EK2+CnyTw/Cy3y5Xv7DlFLHcWRZtm2bnAhlNKYjrGkaSPB4LQqhi812w8/vAV+Vpw5N01QUBQoAoAx99IISYLqLIfXr5/tR4J9fhfX7qq7rEcbCTtd1wHg8mPZiVVWh/DSYyTA/y7YO+gEC/TAO7AzBkkPZTTe94QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://refactoring.guru/design-patterns/proxy&apos; title=&apos;&apos; src=&apos;/static/ac9af4748c08e95b3faa431f867fc032/ca1dc/1.png&apos; srcset=&apos;/static/ac9af4748c08e95b3faa431f867fc032/e7570/1.png 170w,
/static/ac9af4748c08e95b3faa431f867fc032/f46e7/1.png 340w,
/static/ac9af4748c08e95b3faa431f867fc032/ca1dc/1.png 680w,
/static/ac9af4748c08e95b3faa431f867fc032/02d09/1.png 1020w,
/static/ac9af4748c08e95b3faa431f867fc032/3adb2/1.png 1114w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://refactoring.guru/design-patterns/proxy&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h2&gt;프록시 패턴&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;프록시 패턴은 대상 객체에 접근하기 전 그 접근에 대한 흐름을 가로채서 대상 객체 앞단의 인터페이스 역할을 하는 디자인 패턴&lt;/li&gt;
&lt;li&gt;이를 통해 객체의 속성. 변환 등을 보완하며 보안, 데이터검증, 캐싱, 로깅에 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/59f01d6ff275cdc96213281fb27ba879/bbbf7/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.64705882352942%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAAB7UlEQVR42o2T22sTURDG81frU18UpCDig/TBC8WC2EpeLFhaaYkSK1VJiklsjEl3k81ms9nLSTbp5raX/Dwb02BpSjswnLNnzn7nm5lvUpZloes6vu+T2Gw2IwxD4jiee7JPzu5qKcdxUFUV27YJoxhhNmh+eU1u9xmFvQ20r29wOgbjSUAkwW8FFEJgmia2ZJrsx8MBXquMq/1CNM/o6mUGnqDXdaU7BNMxURTdDHhT4DLNse/R+rZDNv2UzPYT6tkthj3ryp0rgMnhNU/qt2AxEB2+b69x9Ooep+kHqHuP6NvaPBbH0fKfWxmyuBRMRhh/clTzGZSfn7GV/LwsNzJchRUEERPZBM/rI3oe/iTEEX1MWzCSMdHr47hdBhc+k2k4b+bKlBOLZLBdPKRw8JIfH55TyWxi/D6hZbRp1BVc2ThRPkI/eUvh4yZ27h1uo7RkfI1hIKVRPHjB8dZ98umH1PfXKR+/xx9NGY+GdCXj0v4GuZ01SrvrtA4fY5xlF4AxKc/zMAyD4XC4fMVtndNRClI2ZYRWou+2lw8mYreaFYzaKY6UllMvzht3WfeUoih8ymSoVCrUqlVU+a1pOrVzFUXVuPhvgu40KQkz27KxOhZmu00yisnaNlo4tkUYBKsVINP7t86WikgA/wI4R4yE3mE9UQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/59f01d6ff275cdc96213281fb27ba879/ca1dc/2.png&apos; srcset=&apos;/static/59f01d6ff275cdc96213281fb27ba879/e7570/2.png 170w,
/static/59f01d6ff275cdc96213281fb27ba879/f46e7/2.png 340w,
/static/59f01d6ff275cdc96213281fb27ba879/ca1dc/2.png 680w,
/static/59f01d6ff275cdc96213281fb27ba879/02d09/2.png 1020w,
/static/59f01d6ff275cdc96213281fb27ba879/bbbf7/2.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;클라이언트가 어떤 일에 대한 요청(&lt;code class=&quot;language-text&quot;&gt;RealSubject&lt;/code&gt;의 &lt;code class=&quot;language-text&quot;&gt;request()&lt;/code&gt; 메서드 호출)을 하면, Proxy가 대신 &lt;code class=&quot;language-text&quot;&gt;RealSubject&lt;/code&gt;의 &lt;code class=&quot;language-text&quot;&gt;request()&lt;/code&gt;메서드 호출을 하고 그 반환 값을 클라이언트에게 전달합니다.&lt;/p&gt;
&lt;p&gt;위 그림을 코드로 구현해 보겠습니다.&lt;/p&gt;
&lt;h3&gt;&lt;code class=&quot;language-text&quot;&gt;Subject.interface&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Subject&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;&lt;code class=&quot;language-text&quot;&gt;RealSubject.class&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RealSubject&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Subject&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Proxy Pattern&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;&lt;code class=&quot;language-text&quot;&gt;Proxy.class&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Subject&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RealSubject&lt;/span&gt; realSubject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RealSubject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RealSubject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 프록시가 실제 메소드를 호출한다.&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;&lt;code class=&quot;language-text&quot;&gt;main.class&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Subject클래스의 메소드를 호출하는이 아닌 프록시클래스의 메소를 호출한다.&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Subject&lt;/span&gt; subject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;subject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 내부적으로 Subject의 메소드를 호출한다.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 코드에서 인터페이스를 중간에 두어서 구체클래스들에게 영향을 받지 않도록 구성되어 있고, 직접 접근하지 않고 Proxy를 통해 한번 더 우회하여 접근하게 되어있습니다. &lt;/p&gt;
&lt;h3&gt;프록시 패턴을 사용하는 이유&lt;/h3&gt;
&lt;h4&gt;1. 흐름을 제어할 수 있다.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/486a187313415ec4dc8ea2bd74b77652/bbbf7/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 27.058823529411764%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA6klEQVR42m2QSUsDQRCF88P14DnggjGKBg+j/ppgJF7ikJmBdnZm3/d5oQonBMyDD7qpqve6a4Y/tW0Lx3Fg2zbKssQwDOj7nqEzQRrHEbufHdafa2y/t6jrGqeaTU1U0HUdqqoiyzI2raoKRVEwdG6ahgNWry+4vLrA/HqOKIqOQUdDGjYMA7Isw/d9uK4LTdMYCpigwCAIIL1LuF/e4fF5ifCcIX0njmOIXwHTNPlFaZoiDEMkScJ4nsfBtJq3Dwm3ixs8PC24558hqes6CCGgKAryPOc7DRPTHqchy7Kw+dpgr+y5drrDA3tHdi+EbGFnAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://refactoring.guru/design-patterns/proxy&apos; title=&apos;&apos; src=&apos;/static/486a187313415ec4dc8ea2bd74b77652/ca1dc/3.png&apos; srcset=&apos;/static/486a187313415ec4dc8ea2bd74b77652/e7570/3.png 170w,
/static/486a187313415ec4dc8ea2bd74b77652/f46e7/3.png 340w,
/static/486a187313415ec4dc8ea2bd74b77652/ca1dc/3.png 680w,
/static/486a187313415ec4dc8ea2bd74b77652/02d09/3.png 1020w,
/static/486a187313415ec4dc8ea2bd74b77652/bbbf7/3.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://refactoring.guru/design-patterns/proxy&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;위 사진처럼 많은 양의 리소스를 필요로 하는 상황에서 DB쿼리가 매우 느려질 수 있다. 이런 상황에서는 지연초기화를 위한 코드 작성을 필요로 하는데 이를 모든 클래스에 직접 넣게 되면 많은 코드중복이 발생하게 된다. &lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8270a5a57b09c538703ec626fbb07533/bbbf7/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 27.058823529411764%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA4klEQVR42mVQXWuEMBC8n16hpT2oR/uTrH3Qal8v9R4VLFrF+IWi0enNgnJwA0uyyWQyswfcQGuNNE3Rti2WZcE8zxiGAeM4wixm55VlibM6Q/0o6FrL2bqush42kjEGWZYhiiJ5wCqKAl3Xoaoq1HUtHML5cGA9PsB6suAHvpzRwC7IJs9zRJcLfq8OKUaRpmmQJMkuzj0/cFwHpzcbp3cb4Xd4L0i7JDJuHMcSnY5YjE/hvu+lJ9xPF8fXZxztFwRhcC+4gZGVUuKGQtM0yfw4xy0u8Xe993wP3pcn3NsZ/gM+yHZQ8i2fVgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;https://refactoring.guru/design-patterns/proxy&apos; title=&apos;&apos; src=&apos;/static/8270a5a57b09c538703ec626fbb07533/ca1dc/4.png&apos; srcset=&apos;/static/8270a5a57b09c538703ec626fbb07533/e7570/4.png 170w,
/static/8270a5a57b09c538703ec626fbb07533/f46e7/4.png 340w,
/static/8270a5a57b09c538703ec626fbb07533/ca1dc/4.png 680w,
/static/8270a5a57b09c538703ec626fbb07533/02d09/4.png 1020w,
/static/8270a5a57b09c538703ec626fbb07533/bbbf7/4.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;https://refactoring.guru/design-patterns/proxy&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;위 사진처럼 프록시객체를 사용한다면 프록시객체가 먼저 리소스요청을 받게 되고 흐름을 제어하면서 DB에 쿼리를 날릴 수 있게 된다.&lt;/p&gt;
&lt;h4&gt;2. 실제 메서드가 호출되기 이전에 필요한 기능(전처리등의)을 구현객체 변경 없이 추가할 수 있다.&lt;/h4&gt;
&lt;p&gt;코드변경의 최소화&lt;/p&gt;
&lt;h4&gt;3. 캐시를 사용할 수 있다.&lt;/h4&gt;
&lt;p&gt;프록시가 내부캐시를 통해 데이터가 캐시에 존재하지 않는 경우에만 주체클래스에서 작업이 실행되도록 할 수 있다. &lt;/p&gt;
&lt;h2&gt;마치며&lt;/h2&gt;
&lt;p&gt;프록시 패턴은 중요한 디자인 상황에서 객체에 대한 간접적인 접근을 제공하면서, 프록시는 코드의 변화에 대응하는 데 도움이 되어 유지보수성을 향상시키는데 기여한다.
그러나 동시에 프록시 패턴을 적용할 때는 코드 중복, 복잡성, 그리고 성능 저하와 같은 단점들도 고려해야 한다. 이러한 측면들을 극복하기 위해서는 디자인을 신중하게 계획하고 패턴을 적용할 때의 상황을 명확히 이해해야 한다고 생각한다.
프록시 패턴은 어떤 상황에서는 필수적인 해결책이 될 수 있지만, 언제 사용해야 하는지에 대한 판단이 필요하다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Git 기본 명령어]]></title><description><![CDATA[Git 저장소 생성 기본 브랜치 이름 변경 현재 상태 확인 전체 로그 확인 Staging area로 파일 이동시키기 저장소 복제 및 다운로드 파일을 Local repository에 저장하고 버전을 기록(commit) Remote repository…]]></description><link>https://hoonblog.netlify.app/git-command/</link><guid isPermaLink="false">https://hoonblog.netlify.app/git-command/</guid><pubDate>Tue, 27 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ccb3ca40f8af43f1f993170f0309c52e/0eb09/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 65.29411764705883%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeUlEQVR42mP4EGBMNmKgnuYgUxBCFgk0ASE4G06iaw42++Cl895L90OQGUgF2JT3vvof/AxAsv5G7330PvgZgkhMze9dVb+0Fn4uT3zvpg5S6qn9Idz6S036xxgnkHFBpp8rk7+0FnzOC4MaB9UMtMdb99vU5t8nD/w6uudTbujHeJfv8/u/zez8vnT6r0M7P6X5fC5P+NpW9KUy+duEuk8Z/u+9dYG6GEA6ffU/Rjv8+/T+97ULP3dv+LFlBdD+35fPfO2t+rFp2Y9tqz8mun2pSftcHv+1qxzols9FUTDNYJvfe+l8acj+c/vqrzNHPkbafanL/PPg1vel075UpXxtKfiU7Pk5Pxyo89vkxq991R+TPUE+h2qG6HdTB/rqY5rve1c1oLM/16R9SvV+764BNBcUbAHGnwsivzTmAgWBLoWEOUpov/fUAhkJDHagNJDtrQeNPKBSYBACI8JbF3toQ2MLqNTfCBxVwAgzxUgFZsgJgWHAkicAJOaXXaCcWe4AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/ccb3ca40f8af43f1f993170f0309c52e/0eb09/1.png&apos; srcset=&apos;/static/ccb3ca40f8af43f1f993170f0309c52e/e7570/1.png 170w,
/static/ccb3ca40f8af43f1f993170f0309c52e/f46e7/1.png 340w,
/static/ccb3ca40f8af43f1f993170f0309c52e/0eb09/1.png 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Git 저장소 생성&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git init&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;기본 브랜치 이름 변경&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git config&lt;span class=&quot;token parameter&quot;&gt; --global&lt;/span&gt; init.defaultBranch 변경할_브랜치_이름&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;현재 상태 확인&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git status&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;전체 로그 확인&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git log&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Staging area로 파일 이동시키기&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git add .&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;저장소 복제 및 다운로드&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git clone https://github.com/{GITHUB_NAME}/{REPOSITORY_NAME}.git&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;파일을 Local repository에 저장하고 버전을 기록(commit)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git commit&lt;span class=&quot;token parameter&quot;&gt; -m&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Remote repository로 업로드&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git push origin master&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;원격 저장소의 변경 내용을 현재 디렉토리로 가져오기 (pull)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git pull&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Remote repository와 Local repository를 연결&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git remote&lt;span class=&quot;token parameter&quot;&gt; --v&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;브랜치 삭제&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git branch&lt;span class=&quot;token parameter&quot;&gt; -d&lt;/span&gt; [브랜치명]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;현재 브랜치에 다른 브랜치 수정사항 병합&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git merge [다른 브랜치명]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;복사할 코드가 있는 Rmote Repository의 코드를 내 Rmote Repository로 복사&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;$ Fork&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;상대의 Rmote Repository 주소를 내 Local Repository와 연결&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git rmote add pair [상대의 Rmote Repository 주소]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;연결된 주소들의 목록 확인&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git rmote&lt;span class=&quot;token parameter&quot;&gt; -v&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;파일 수정&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;$ nano [파일이름]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;수정한 파일을 staging area에 추가 (commit 전)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git add [파일이름]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;commit이 되지 않은 파일을 폐기&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git restore [파일이름]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;staged된 파일을 이전 상태로 되돌림&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&lt;span class=&quot;token command&quot;&gt;$ git restore&lt;span class=&quot;token parameter&quot;&gt; --staged&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Java 문자열(String)]]></title><description><![CDATA[자바에서 String은 텍스트 데이터를 저장하고 조작하는 데 사용되는 클래스입니다. String 클래스는 자바의 내장 클래스로, java.lang 패키지에 속해 있으므로 추가적인 임포트 없이 사용할 수 있습니다.
String…]]></description><link>https://hoonblog.netlify.app/java-string/</link><guid isPermaLink="false">https://hoonblog.netlify.app/java-string/</guid><pubDate>Tue, 27 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;자바에서 &lt;strong&gt;String은 텍스트 데이터를 저장하고 조작하는 데 사용되는 클래스입니다.&lt;/strong&gt; String 클래스는 자바의 내장 클래스로, java.lang 패키지에 속해 있으므로 추가적인 임포트 없이 사용할 수 있습니다.
String 객체는 한 번 생성되면 변경할 수 없는 불변(immutable) 객체이기 때문에 문자열을 수정하면 실제로는 새로운 문자열 객체가 생성되는 것이며, 원래의 문자열은 그대로 유지됩니다. &lt;/p&gt;
&lt;p&gt;String 객체는 문자열 리터럴로 초기화하거나 new 키워드를 사용하여 생성할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 문자열 리터럴을 사용한 초기화&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dudu&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// new 키워드를 사용한 생성&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8af179174b9636609ee45852a8925f07/b38ab/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.294117647058826%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAACIklEQVR42oXR3W/SUBgG8P2NXigxarKYLLty3qpLvFiicTFmJmNu4GbcQuI0zjkd6BAnH0MYK4yWAh0tpR/Yln7RnrW0lLYCW4Z3vnlyzpuc/M7NM+X/byzbaVFMg2jyguj5vud5V09TF1dPZIw2bvGkxbf6PbM/GBSavc+n1nfU/oV2E7A8PFM1/Tduxav9fdjJNOwJ1oiyUE5rWEHDjg0ATKu/B6mLUSUY57MQBqE0RnfrpIQQUiTXW0laO0XzEruOrVTzSi2n1vNmo+ByZ4Zp7RXVxZj8NqujGFkn6I5y3pEBK4KtHHiZ0N+fgDH2XN82TKZmUKjNYjZbH0iU7/W/wmBhXwmlNZLmWwwvaz25a3CyEUqpT6LyVlYd4YEutXMxGUlLcIor/mQLCeX00FHaHyD9wQ734qBzRivD1JoiRooIIS7FxfldIZySRtgztXOiBPCS3ig6DOqwqMtUXF3cyAhz79inUY6XgCDrvKyLCmAF/VmMu7/NLCf4EXaBrMJJqZwUSoduC/Kpkksc+6b05ki4HcYffmqTAqBEsyWatGhgf8DjXXZmk3z+rX2JNSQ59AL0w8Hzfgty8ZxvdF4fSffWT+a30dkIOb0K3VpK3Q0js5HmzCZxZx1f+EJPqho2f1W+O96CCWZ6OTO3UQisVW+8Qq6vlAOrSGANvRlCrwWRRx/xCf53Lj5hJBOiQJkBFUarsPoow2UcmO4S/KiqvzDlOVMfCheXAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;출처: https://www.digitalocean.com/community/tutorials/what-is-java-string-pool&apos; title=&apos;&apos; src=&apos;/static/8af179174b9636609ee45852a8925f07/ca1dc/1.png&apos; srcset=&apos;/static/8af179174b9636609ee45852a8925f07/e7570/1.png 170w,
/static/8af179174b9636609ee45852a8925f07/f46e7/1.png 340w,
/static/8af179174b9636609ee45852a8925f07/ca1dc/1.png 680w,
/static/8af179174b9636609ee45852a8925f07/02d09/1.png 1020w,
/static/8af179174b9636609ee45852a8925f07/b38ab/1.png 1168w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;출처: https://www.digitalocean.com/community/tutorials/what-is-java-string-pool&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;String 클래스는 다양한 메서드를 제공하여 문자열을 조작하고 검색하는 데 사용할 수 있습니다. 일반적인 메서드에는 문자열의 길이를 반환하는 &lt;code class=&quot;language-text&quot;&gt;length()&lt;/code&gt;, 두 문자열을 연결하는 &lt;code class=&quot;language-text&quot;&gt;concat()&lt;/code&gt;, 특정 문자 또는 문자열을 포함하는지 확인하는 &lt;code class=&quot;language-text&quot;&gt;contains()&lt;/code&gt;, 문자열을 분할하는 &lt;code class=&quot;language-text&quot;&gt;split()&lt;/code&gt;, 대소문자 변환을 수행하는 &lt;code class=&quot;language-text&quot;&gt;toLowerCase()&lt;/code&gt; 와 &lt;code class=&quot;language-text&quot;&gt;toUpperCase()&lt;/code&gt; 등이 있습니다.&lt;/p&gt;
&lt;h2&gt;&lt;code class=&quot;language-text&quot;&gt;length()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;문자열의 length() 메서드는 해당 문자열의 길이(문자의 개수)를 반환합니다. &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 문자열 리터럴을 사용한 초기화&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dudu&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// new 키워드를 사용한 생성&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//출력값: 6&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//출력값: 4&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;&lt;code class=&quot;language-text&quot;&gt;concat()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;자바의 concat() 메서드는 문자열(String)에 다른 문자열을 이어붙일 때 사용하는 메서드입니다. &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 문자열 리터럴을 사용한 초기화&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dudu&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// new 키워드를 사용한 생성&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//concat을 이용하여 이어붙임&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//출력값: Hello!dudu&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;&lt;code class=&quot;language-text&quot;&gt;contains()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;자바의 contains() 메서드는 문자열(String)이 특정 문자열을 포함하고 있는지를 확인하기 위해 사용되는 메서드입니다. contains() 메서드는 호출된 문자열에 대상 문자열이 포함되어 있는 경우 true를 반환하고, 포함되어 있지 않은 경우 false를 반환합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 문자열 리터럴을 사용한 초기화&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dudu&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// new 키워드를 사용한 생성&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;boolean&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;du&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//contains을 이용하여 문자열을 포함하는지 확인&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//출력값: true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;변수를 사용하여 동적으로 포함 여부를 확인할 수도 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 문자열 리터럴을 사용한 초기화&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, dudu&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// new 키워드를 사용한 생성&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;boolean&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//contains을 이용하여 문자열을 포함하는지 확인&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//출력값: true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;contains()&lt;/code&gt; 메서드는 대소문자를 구분하여 문자열을 비교합니다. 따라서 &quot;World&quot;와 &quot;world&quot;는 서로 다른 문자열로 처리됩니다. 문자열을 대소문자 구분 없이 비교하고 싶다면, &lt;code class=&quot;language-text&quot;&gt;toLowerCase()&lt;/code&gt; 또는 &lt;code class=&quot;language-text&quot;&gt;toUpperCase()&lt;/code&gt;를 이용하여 대문자 또는 소문자로 통일한 후 &lt;code class=&quot;language-text&quot;&gt;contains()&lt;/code&gt; 메서드를 사용할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 문자열 리터럴을 사용한 초기화&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, dudu&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// new 키워드를 사용한 생성&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;//toUpperCase를 이용하여 name2 문자열을 대문자로 변경 후 특정 문자열을 포함하는지 확인&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;boolean&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toUpperCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DUDU&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//출력값: true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Java 정수타입]]></title><description><![CDATA[자바는 정수타입을 4가지 타입으로 나눌 수 있습니다. byte, short, int, long 4가지이며, 각각의 차지하는 메모리가 다르고, 나타낼수 있는 숫자의 범위가 다르다. 타입 메모리 범위 byte 1byte -128() ~ 12…]]></description><link>https://hoonblog.netlify.app/java-integer-type/</link><guid isPermaLink="false">https://hoonblog.netlify.app/java-integer-type/</guid><pubDate>Sun, 25 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;자바는 정수타입을 4가지 타입으로 나눌 수 있습니다.&lt;/p&gt;
&lt;p&gt;byte, short, int, long 4가지이며, 각각의 차지하는 메모리가 다르고, 나타낼수 있는 숫자의 범위가 다르다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;center&quot;&gt;타입&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;메모리&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;범위&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;byte&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;1byte&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;-128(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mn&gt;7&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;-2^{7}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.897438em;vertical-align:-0.08333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141079999999999em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) ~ 127(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mn&gt;7&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2^{7} - 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.897438em;vertical-align:-0.08333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141079999999999em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222222222222222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222222222222222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.64444em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;short&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;2byte&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;-32,768(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mn&gt;15&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;-2^{15}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.897438em;vertical-align:-0.08333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141079999999999em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) ~ 32,767(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mn&gt;15&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2^{15} - 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.897438em;vertical-align:-0.08333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141079999999999em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222222222222222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222222222222222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.64444em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;int&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;4byte&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;-2,147,483,648(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mn&gt;31&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;-2^{31}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.897438em;vertical-align:-0.08333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141079999999999em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) ~ 2,147,483,647(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mn&gt;31&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2^{31} - 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.897438em;vertical-align:-0.08333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141079999999999em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222222222222222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222222222222222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.64444em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;long&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;8byte&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;-9,223,372,036,854,775,808(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mn&gt;63&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;-2^{63}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.897438em;vertical-align:-0.08333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141079999999999em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) ~ 9,223,372,036,854,775,807(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mn&gt;63&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2^{63} - 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.897438em;vertical-align:-0.08333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141079999999999em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222222222222222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222222222222222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.64444em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 각 데이터 타입의 범위에 맞는 값을 할당 &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;byte&lt;/span&gt;  byteNum  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;short&lt;/span&gt; shortNum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;   intNum   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;123456789&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt;  longNum  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12345678910L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 각 데이터 타입의 범위에 벗어난 값을 할당하고 있어 에러가 발생 &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;byte&lt;/span&gt;  byteNum  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;130&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;short&lt;/span&gt; shortNum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;123456&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;   intNum   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12345678910&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 숫자가 길면 언더바로 구분 &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;   intNum   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12_345_678_910&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt;  longNum  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12_345_678_910L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;long타입의 경우에는 값 뒤에 접미사 L,l 을 붙여주어서 구분합니다. (일반적으로 대문자 L을 사용) &lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[Java 정수형의 오버플로우와 언더플로우]]></title><description><![CDATA[코드를 작성 후 실행 중일때, 타입의 정해진 범위를 넘는 경우가 발생할 수 있다. 예를 들어 byte타입의 경우 127까지 표현 가능하지만, byte타입이 127을 넘을 결우 오버플로우가 발생한다. 반대의 경우 byte타입이 -12…]]></description><link>https://hoonblog.netlify.app/java-overflow-underflow/</link><guid isPermaLink="false">https://hoonblog.netlify.app/java-overflow-underflow/</guid><pubDate>Sun, 25 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;코드를 작성 후 실행 중일때, 타입의 정해진 범위를 넘는 경우가 발생할 수 있다.&lt;/p&gt;
&lt;p&gt;예를 들어 byte타입의 경우 127까지 표현 가능하지만, byte타입이 127을 넘을 결우 오버플로우가 발생한다.&lt;/p&gt;
&lt;p&gt;반대의 경우 byte타입이 -128보다 값이 적을경우에 최소값을 넘기 때문에 언더플로우가 발생한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//정수 오버플로우, 언더플로우의 예시&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Of&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;125&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uf&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;125&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;byte&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Of&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;byte&lt;/span&gt; result2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Uf&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 오버플로우 발생 : -121&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 언더플로우 발생 : 121&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;컴파일 에러가 발생하지 않았지만, 제대로된 값을 얻지 못했다. 그 이유는 byte형의 범위를 넘었기 때문이다. 올바른 값을 얻기위에서는 byte타입이 아닌 int타입이어야 한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;정수형의 오버플로우와 언더플로우는 컴파일러가 오버플로우, 언더플로우를 무시해서  잘못된 값이 저장되기 때문에 발생한경우 알아보기 힘들어서 매우 위험하다. 정해진 연산을 처리하면서 잘못된 결과로 프로그램의 오작동을 발생할수 있고, 보안에 취약한 부분을 내포하게 된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;오버플로우와 언더플로우를 피하는 안전한 코딩법&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;언어 ・ 플랫폼별 정수 타입의 범위를 확인하여 사용&lt;/li&gt;
&lt;li&gt;정수형 변수를 연산에 사용하는 경우 결과 값의 범위를 체크하는 모듈을 사용&lt;/li&gt;
&lt;li&gt;외부입력값을 동적 메모리 할당에 사용하는 경우, 변수값이 적절한 범위 내에 존재하는지 값인지 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;타입별 범위 확인&lt;/h3&gt;
&lt;p&gt;각 타입별 허용 범위는 각 타입별 클래스의 MIN&lt;em&gt;VALUE(최소값), MAX&lt;/em&gt;VALUE(최대값) 메소드를 통해 타입의 범위를 확인할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out println&lt;span class=&quot;token string&quot;&gt;&quot;char: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Character&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MIN_VALUE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; ~ &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Character&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MAX_VALUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;byte: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Byte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MIN_VALUE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; ~ &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Byte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MAX_VALUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;short:&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Short&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MIN_VALUE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; ~ &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Short&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MAX_VALUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;int: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MIN_VALUE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; ~ &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MAX_VALUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;long: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MIN_VALUE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; ~ &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MAX_VALUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;float: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MIN_VALUE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; ~ &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MAX_VALUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;double:&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MIN_VALUE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; ~ &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MAX_VALUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;결과&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;char: 0 ~ 65535
byte: -128 ~ 127
short: -32768 ~ 32767
int: -2147483648 ~ 2147483647
Long: 9223372036854775808 ~ 9223372036854775807
float: 1.4-45 ~ 3.4028235E38
double: 4.9E-324 ~ 1.7976931348623157E308&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[☕️Java 개발 환경 구축 (2)]]></title><description><![CDATA[이번 글에서는 IntelliJ 설치를 해보려고 합니다. IntelliJ는 IDE 중 하나로 stackOverflow 커뮤니티의 매년 개발자 설문조사 실행하는데 "전 세계 개발자에게 인기 있는 개발툴 TOP 5"에 들어갈 정도로 많이 사용하는 IDE…]]></description><link>https://hoonblog.netlify.app/development-environment2/</link><guid isPermaLink="false">https://hoonblog.netlify.app/development-environment2/</guid><pubDate>Wed, 10 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;이번 글에서는 IntelliJ 설치를 해보려고 합니다.&lt;/p&gt;
&lt;p&gt;IntelliJ는 IDE 중 하나로 stackOverflow 커뮤니티의 매년 개발자 설문조사 실행하는데 &quot;전 세계 개발자에게 인기 있는 개발툴 TOP 5&quot;에 들어갈 정도로 많이 사용하는 IDE 중 하나로 알고 있다.&lt;/p&gt;
&lt;h3&gt;IntelliJ의 장단점&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f28992c3324c30394a5b444c6d28f990/92aea/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 27.647058823529413%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABDklEQVR42j1PSXLCQBDzswMhFyofNOCF4G0c433DBxfFRZEmZQ4qqbun1Rpnfw7weQ7/cQlx9K44kHcnHx+uh53r48Del/fDPtknU6v+DiLsTwHkIVbfcX0flzCE63k4B8Gbr3GMJM8RG4OybVHUNdLfwsLc77aflyXaYcTweKCfZqyvF5wsTWGInA9MllnkJkPFxyUXxeMwoKNpS1PVDbmuKrRNY2di1QuNnZhJoiiCoaG0UHOh73vLLY0GLuVMe7vd3kiSBBmPi7Vb0XCaJjhqbMOUScUy3R5Ly7BhijsTCzqkuigKW0t3XYd1XeHo2pZySygtc82kZaikSiA8+LVlWaye59nW4zji+XziD8KxrjxKyU7MAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;IntelliJ의 장단점&apos; title=&apos;&apos; src=&apos;/static/f28992c3324c30394a5b444c6d28f990/ca1dc/1.png&apos; srcset=&apos;/static/f28992c3324c30394a5b444c6d28f990/e7570/1.png 170w,
/static/f28992c3324c30394a5b444c6d28f990/f46e7/1.png 340w,
/static/f28992c3324c30394a5b444c6d28f990/ca1dc/1.png 680w,
/static/f28992c3324c30394a5b444c6d28f990/02d09/1.png 1020w,
/static/f28992c3324c30394a5b444c6d28f990/9d567/1.png 1360w,
/static/f28992c3324c30394a5b444c6d28f990/92aea/1.png 1720w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;IntelliJ의 장단점&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;1. &lt;a href=&quot;https://www.jetbrains.com/ko-kr/idea/download/?section=mac#section=mac&quot;&gt;IntelliJ 다운로드&lt;/a&gt;에 접속 후 다운로드&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/179015429610b795718070e8b2ee61b8/bbbf7/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 31.76470588235294%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABGElEQVR42oVRu07DMBTtzsrAJ7LyCYgJMfFY6BewIt4VLFS0QoBEJghDk1AUCgkhuK5fiX2wXTUgVYgjXfn6+txzH27Bouz2sbuyitPrxF0hhMRw+II0fUUURYjjBJRS/AdjDFrOCQ/2sbiwhOW1I/9QKQnOxhCMQlfSErUn2xRobX1t/hT1gqIguOjGeEyVDzKu8DDIkIwYsq+6IUeDZ9ze3CMIApRl2XTlijgcn5xNBSnnmDDiO3AgDNi7Emh3xji8k9BmGj/vXGJjfRtbmzsIw6c5wV6vPxM0KOlsLKCuKryNUnzk797yPEeWZSiKT79LZ4wxEEJQWe7cyBNhwNXPXlxFIQSklP78bS6mlGr8uq6bRtynfAMfeMaMdl2SRQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/179015429610b795718070e8b2ee61b8/ca1dc/2.png&apos; srcset=&apos;/static/179015429610b795718070e8b2ee61b8/e7570/2.png 170w,
/static/179015429610b795718070e8b2ee61b8/f46e7/2.png 340w,
/static/179015429610b795718070e8b2ee61b8/ca1dc/2.png 680w,
/static/179015429610b795718070e8b2ee61b8/02d09/2.png 1020w,
/static/179015429610b795718070e8b2ee61b8/bbbf7/2.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;2. IntelliJ 아이콘을 화살표 방향대로 드래그&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/cd4c2b91b79c199aab19b574b4240e4c/3d024/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.88235294117648%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAACqElEQVR42pWUS0wTQRiAEaInj8aERDnUxoPh0EJtQJ6mPCJqgsYmDR60iSFQORoOHuwV40kvmnDRtkBtooka8QFEFkRebYEEA6jFAlJagZbutvue+Z1tywpCTfiTb+fP7P7f/JnZTE7O3zhEyFMw7yA9Z85T35nNe7Db7bmZ+nQUHCvIv3G+qtfSVDlsLDs3WGSsonTFZVSVqZGyWKxUXXUNdeniFepC3WXKSOaLdSVp9KWDBn3p5yJdySuNRlOgCk+cNp2taxsQq21voOGmB3c02sHZYAX3dQt86rDB+Pvn4PfPgM/rh8kJn8rEuBdP+WZgeGgkYbVay1XhrZaWiu63k4K+tBG/vt0hB+/eQ2udDxDMjyBAHAKAbMgESCaTjM1mM6nCq01NlaHAd6nf8QxiU2OYCa8AzXMgYQwIkypZJhA3QSK5KMmZUcKKMB6PJ1tbW2tUYW1tbSXH85LyUkCAU1+RBxJROlHZE6lJhmH2Cnmek8jCEFtcx8GxIPhmWYhEEMgC6ZAsJfKkmoyhLQ5WNlmgWRFYXswu5Fg21eFM50fcVngNDOU2GJ0TgI2ysBaKwXIwChzJn05Hob3vN9wfjcGHH3RKSO8nTGaEDx/PY22+EY6fLIYxvwQJehOCS0EI/FwEjonCi4AA7UM03KFoeLmQwIDl/YXbezjsS+JHzml40j0LSwFZ3Sic2cIvc8vQuxCDd9+24GuYSXdI/yOsr6+vYFlWUOrW16JyZHUdRVY3UDyWQEpIkpSCnDTi2AQKh36hjUgYiQIvp4U03dzcbNol5DMdZjvOLKEeyq7/UKvVnnG73d1dXV0DDoezz+Fw9Su4XP/H6XT29fT0DJDcZTAYCndeCkcJGoKeUHRAdIRTGYd6QeR6vd7DHo/nyEFR6hS2ZX8A/eTPr28AXqcAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/cd4c2b91b79c199aab19b574b4240e4c/ca1dc/3.png&apos; srcset=&apos;/static/cd4c2b91b79c199aab19b574b4240e4c/e7570/3.png 170w,
/static/cd4c2b91b79c199aab19b574b4240e4c/f46e7/3.png 340w,
/static/cd4c2b91b79c199aab19b574b4240e4c/ca1dc/3.png 680w,
/static/cd4c2b91b79c199aab19b574b4240e4c/02d09/3.png 1020w,
/static/cd4c2b91b79c199aab19b574b4240e4c/3d024/3.png 1134w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[☕️Java 개발 환경 구축 (1)]]></title><description><![CDATA[오늘은 자바의 개발 환경을 구축하기 위해 JDK 설치와 IntelliJ 설치해보려고 한다. Mac M1 사용중이기 때문에 Mac 기반으로 작성 되었습니다. JDK는 Zulu openJDK 사용 IntelliJ는 Community Edition…]]></description><link>https://hoonblog.netlify.app/development-environment1/</link><guid isPermaLink="false">https://hoonblog.netlify.app/development-environment1/</guid><pubDate>Tue, 09 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;오늘은 자바의 개발 환경을 구축하기 위해 JDK 설치와 IntelliJ 설치해보려고 한다.&lt;/p&gt;
&lt;p&gt;Mac M1 사용중이기 때문에 Mac 기반으로 작성 되었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JDK는 Zulu openJDK 사용&lt;/li&gt;
&lt;li&gt;IntelliJ는 Community Edition 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Zulu openJDK의 장점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;멀티 플랫폼 지원: Zulu OpenJDK는 Windows, macOS, Linux 및 다른 운영 체제에서 실행할 수 있다. 이는 Java 프로그램을 개발하고 배포하는 데 있어서 대규모 시스템에서 이식성이 높은 솔루션을 제공한다.&lt;/li&gt;
&lt;li&gt;Java SE 호환성: Zulu OpenJDK는 Java SE의 최신 버전과 호환된다. 이는 Java SE API와 플랫폼 특성을 모두 지원하며 Java SE에서 작성된 코드가 Zulu OpenJDK에서 작동할 수 있도록 한다.&lt;/li&gt;
&lt;li&gt;안전한 애플리케이션 개발: Zulu OpenJDK는 Java 애플리케이션에서 발생할 수 있는 보안 취약점을 예방하는 기능을 제공한다. 이는 Java 애플리케이션 개발자들에게 높은 수준의 보안성을 제공합니다. 또한 Zulu OpenJDK는 업데이트와 유지보수가 지속적으로 이루어지며, Azul Systems는 기술 지원과 컨설팅 서비스를 제공하므로 개발자들이 안심하고 Java 애플리케이션을 개발할 수 있도록 도와준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;1. &lt;a href=&quot;https://www.azul.com/downloads/?version=java-11-lts&amp;#x26;os=macos&amp;#x26;architecture=arm-64-bit&amp;#x26;package=jdk#zulu&quot;&gt;Zulu openJDK 다운로드 페이지&lt;/a&gt; 접속 후 Java의 버전, OS, Architecture 를 선택&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e084b554f44754bb56af2b586967a282/bbbf7/1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 31.76470588235294%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABM0lEQVR42k2Qy0oDQRBF51f9EnHjRheu3KkgfkEIqBAIiEIIogYRcaeJcXSCmWe/H9eqHoMWFFPVVX3unc7m7znuZ8+w1oHDew8pJbTWKYWQMMbQ3FItEGi+CUF7XddhfDXFzu4hLkbXyIrVGotljhB4MdI3ENQlgHMuCXD+rzl5zzpLNyKK4hsPZCr/XCHbqNWVRtOSExNRlgLFVwWtfKrrmtxKj6qUaBsNJXyaMVRrQ2J/rjNEcuUjVEsuDKm7iI7AQpBLFdDUBm1nYTWfWygCKxFQrRU0PYWx1BM0EodZWfwlD29m2D4a4HzylHpnAykHxAAY7ciJTbWnM55xzBcfGAzHeH1bpj4mYOyRp6MptvbPcHw5ST2r8y9xGGNTJiHHb9ifzx5fsHdwgtu73kQIET/zkcot8rAxWQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;1&apos; title=&apos;&apos; src=&apos;/static/e084b554f44754bb56af2b586967a282/ca1dc/1.png&apos; srcset=&apos;/static/e084b554f44754bb56af2b586967a282/e7570/1.png 170w,
/static/e084b554f44754bb56af2b586967a282/f46e7/1.png 340w,
/static/e084b554f44754bb56af2b586967a282/ca1dc/1.png 680w,
/static/e084b554f44754bb56af2b586967a282/02d09/1.png 1020w,
/static/e084b554f44754bb56af2b586967a282/bbbf7/1.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;2. dmg를 선택하여 다운로드&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a24b76f1ea14858697d7b0dc2e590487/bbbf7/2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 31.76470588235294%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA5klEQVR42qVRu24CMRC8P8wH8Qn0RKKioaGBoBQpoECiQ6IEEekEqSgJHHc+P9aT3bWPtEiMZHm83p0dr4sYIwS1aXURRVT3Gpffijkxb3KccK8NTGuVW+dhrdN7w/dAhGgVyIgsFELgPSX7QJpguMi6oFziIiZNm6ZFy+KB8xzHOxTZIN4/VnjrDTD8XOtZkgIXC8RVcgF4H7Sx4Lv8wWg8x/5wTKbEYSe42B7QnyzxtdnlQq9uBeKCsggpT0VlecZ0tsbxdP4XxAtw1vNK4+j+4iFIHJAnUmf5GUHncL1VPFv3mOEfxgLR9LnsAocAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;2&apos; title=&apos;&apos; src=&apos;/static/a24b76f1ea14858697d7b0dc2e590487/ca1dc/2.png&apos; srcset=&apos;/static/a24b76f1ea14858697d7b0dc2e590487/e7570/2.png 170w,
/static/a24b76f1ea14858697d7b0dc2e590487/f46e7/2.png 340w,
/static/a24b76f1ea14858697d7b0dc2e590487/ca1dc/2.png 680w,
/static/a24b76f1ea14858697d7b0dc2e590487/02d09/2.png 1020w,
/static/a24b76f1ea14858697d7b0dc2e590487/bbbf7/2.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;3. 다운로드 완료 후 실행 하시고 오른쪽 박스 클릭&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f46504fe37c10f8a52872d04ff6bbc6e/bbbf7/3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 87.05882352941177%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAADQElEQVR42p2S32sTWRTH89AHS/G1PhS2Lz4sKOxr0L+gLF3EpSuhG2MVRKSICPugbVPXoq1W2z4oIiIqLrgg6BpE240rNSakoFX7K5v+yK/WNmmSZmYyM0kmc+d+PTM1TUDBXQ/z4d65w/3cM+dcm41id0PDjl3fbd9T31hvr7MRdRW225ubv7c3NTbZm5qa7Y00Vr/Vsm2Pzdaww1aJ7hOneq+PDKK37yzrPnMWPV2buHvOYXBwBP3nL2HgwiD6fu9HN63X0nWml50/N4DO4yd7t4TBYHAIm1EmjP+JuQcTExNXtoQ+n2/YXNR1nVHgS5QKDAWljKLKCKBYIFQdBVlj5l7TsSUMBAKW0DAMRoBzTnOCRmudtsiigTLlohVK0KQ4SuIySnRAQeWWMBgMfC4kEUNNkB1aWSMht7LS1l9Cnj+N7FQnpFAntMg1lIXUJ6G/KvT7/ZZQlhU2PTuP1bV1zND4+s0MHnm8llxKy4g968fSs32IvfoZ4b9/ROTpISipZUsYCNT8cqWGb97OssPHunDvvgcjV+/g5G/9uHHrT0tYUDjCo3fhvXIQvptteH3zCMYGnMjE5i2h3+/7UoYqi8ZWsPIhibVkGkuRZWQ3ctCp7mYdl6b86P5pJy7+sgvDv/6AP/oOg5UZM1v90PvP12tYCVOmCIY1n371HLdPH4T/8X3ks4JZW7aWBx6MeT8X0lnMPM/qsMVmx0GPJBQhZGXIeQ2iWERZM5DLqXi3mGar1LDHz8eH/nOGZpRKRRQpnRKhKjJW0huYjCbxPp5iGQ34a+xFNcPR0fEhuh1IpQosnaFMRA1qUUeZVe6kQVeIo6QbyFCG8ykFUysSwkkZkXWFCTrwaPRFNcMnnvFhWQIScVWPRBQeXsjz6X9FPrMg8rmoxEOJPJ9NSPxtVOCTxDTNw6syX0wqPJZWdYn+yzM2Xs3Q89B7WRaB5bjEEvE8olEJi0siQuEc3s1lMTmXwWQog/cLG5iJ5DAbExBKCFj4IGJxVWQbReryU+/lLWFLS+tel/NoT7ujw+1wuNyOAy6309nhbm93We9tbS73flprc1RHkwPtmzg7jva0tLbutdVEHVFPNHwj9Z8cto9FZJtbGi95JAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;3&apos; title=&apos;&apos; src=&apos;/static/f46504fe37c10f8a52872d04ff6bbc6e/ca1dc/3.png&apos; srcset=&apos;/static/f46504fe37c10f8a52872d04ff6bbc6e/e7570/3.png 170w,
/static/f46504fe37c10f8a52872d04ff6bbc6e/f46e7/3.png 340w,
/static/f46504fe37c10f8a52872d04ff6bbc6e/ca1dc/3.png 680w,
/static/f46504fe37c10f8a52872d04ff6bbc6e/02d09/3.png 1020w,
/static/f46504fe37c10f8a52872d04ff6bbc6e/bbbf7/3.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;4. 계속 눌러주면 설치 완료&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/23371b4f437d98bf36f4974e133ae3f4/bbbf7/4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.88235294117648%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAACC0lEQVR42sWSy27TQBSGgyqWRFZXQNs0dnwZ3++e+FInaRyaYBBtXwAWLKvyFH2BLsijdjFSDmemOG2hQYINI306nrH9+fzj6fVwfJtMpK/nc51SqnUEQaBdtrXWNq2g4bW91Jq60QLT1B4/W1WVPkFHrxuLmN6splNIouIuDnMWITSp2NlszprZijWn70V917SijrMTFvmUhX6GNbvL0xpin95shcqQfLeNGEzNZ5YegKUF4FspFHQGdTGHabWASdngdQPTcgHV+BQil0Li5xC6lLkkhhE6tkJ5aK1zuoDIo8w2InDNGNShDYbigm+nuD6GZfMRPiwvRF0hRYaJgoKLmSG7XLjeCvkkDStse8w8KwHbCAUxigI7A1sPseMEPPyQqIip+gLHCJlnJiAP9KfCGNvHzkTkTljncyixEx6Jv+Ri987PBJ55v4ZyjPyMEPcCHBIyLnJIJOIevR7B4I0KwwN9J3if6RhZkx9F5hMeA7t7EI5cUI4IjAamqLuQDw1GFO/pHnIh/6u/CQ/JH2Wd0Pg/QtxD5YDcS58BRYLjtyrTZPtXobUWxwOPAJc5ZsQPOeiysxNT9cBSI/CMnMXOBNf8B6FyTG4dPBpE9RiKNgJ9NzYJN3l6simT5ebT2Wd2vvwCtlLedr4X/X4/lfrSlfRKuv579q+l/v4Vd3DXVorsIS//kb1O9gMvFVbDO5nnegAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;4&apos; title=&apos;&apos; src=&apos;/static/23371b4f437d98bf36f4974e133ae3f4/ca1dc/4.png&apos; srcset=&apos;/static/23371b4f437d98bf36f4974e133ae3f4/e7570/4.png 170w,
/static/23371b4f437d98bf36f4974e133ae3f4/f46e7/4.png 340w,
/static/23371b4f437d98bf36f4974e133ae3f4/ca1dc/4.png 680w,
/static/23371b4f437d98bf36f4974e133ae3f4/02d09/4.png 1020w,
/static/23371b4f437d98bf36f4974e133ae3f4/bbbf7/4.png 1280w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[🤩 4. 그 외 팁들]]></title><description><![CDATA[파비콘은 어떻게 변경하나요?  에 파비콘 파일이 위치해 있습니다. 이미지 파일을 대체하면 파비콘을 변경할 수 있습니다. 만약 파비콘 파일의 이름을 변경하고 싶다면,  파일의  에서  속성을 변경하셔야합니다. Utterance…]]></description><link>https://hoonblog.netlify.app/other-tips-kr/</link><guid isPermaLink="false">https://hoonblog.netlify.app/other-tips-kr/</guid><pubDate>Sun, 04 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;파비콘은 어떻게 변경하나요?&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;static/favicon.png&lt;/code&gt; 에 파비콘 파일이 위치해 있습니다. 이미지 파일을 대체하면 파비콘을 변경할 수 있습니다.&lt;/p&gt;
&lt;p&gt;만약 파비콘 파일의 이름을 변경하고 싶다면, &lt;code class=&quot;language-text&quot;&gt;gatsby-config.js&lt;/code&gt; 파일의 &lt;code class=&quot;language-text&quot;&gt;gatsby-plugin-manifest&lt;/code&gt; 에서 &lt;code class=&quot;language-text&quot;&gt;icon&lt;/code&gt; 속성을 변경하셔야합니다.&lt;/p&gt;
&lt;h2&gt;Utterance 가 제대로 작동하지 않아요.&lt;/h2&gt;
&lt;p&gt;http 환경에서는 Utterance 가 제대로 작동하지 않을 수 있습니다. 여러분의 웹사이트를 https 환경으로 제공하세요.&lt;/p&gt;
&lt;h2&gt;OG Image 를 설정하고 싶어요.&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;/static&lt;/code&gt; 디렉토리의 &lt;code class=&quot;language-text&quot;&gt;og-image.png&lt;/code&gt; 파일을 여러분이 원하는 이미지 파일로 대체하세요.&lt;/p&gt;
&lt;h2&gt;다른 질문이 있으신가요?&lt;/h2&gt;
&lt;p&gt;이 문서에 댓글을 달거나 gatsby-starter-hoodie 레포지토리에 &lt;a href=&quot;https://github.com/devHudi/gatsby-starter-hoodie/issues&quot;&gt;이슈를 열어주세요&lt;/a&gt;. 여러분의 참여가 gatsby-starter-hoodie 를 더욱 발전시킵니다. 감사해요 😎.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[🤔 3. 작성 가이드]]></title><description><![CDATA[1. 포스트 추가하기  경로에 새로운 마크다운 파일을 생성하여 여러분의 글을 추가할 수 있습니다. 1-…]]></description><link>https://hoonblog.netlify.app/writing-guide-kr/</link><guid isPermaLink="false">https://hoonblog.netlify.app/writing-guide-kr/</guid><pubDate>Sat, 03 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. 포스트 추가하기&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;contents/post&lt;/code&gt; 경로에 새로운 마크다운 파일을 생성하여 여러분의 글을 추가할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;1-1. 포스트 파일 구조&lt;/h3&gt;
&lt;p&gt;새로운 문서를 추가하는 방법에는 두가지가 있습니다. 첫번째는 디렉토리 없이 문서를 생성하는 방법입니다. 만약 여러분이 Javascript 에 관한 문서를 생성한다면, &lt;code class=&quot;language-text&quot;&gt;about-javascript.md&lt;/code&gt; 파일을 &lt;code class=&quot;language-text&quot;&gt;contents/posts&lt;/code&gt; 디렉토리에 추가할 수 있습니다.&lt;/p&gt;
&lt;p&gt;두번째 방법은 먼저 디렉토리를 생성한 뒤, 디렉토리 안에 &lt;code class=&quot;language-text&quot;&gt;index.md&lt;/code&gt; 파일을 추가하는 것 입니다. 이 방법은 문서 내에 여러 이미지 파일 등 부수적인 파일 여러개가 포함되었을 때 유용합니다.&lt;/p&gt;
&lt;p&gt;첫번째 방법으로 생성한 파일명이나, 두번째 방법으로 생성한 디렉토리 이름은 웹사이트에서 고유의 주소를 갖습니다. &lt;code class=&quot;language-text&quot;&gt;https://siteURL/about-javascript&lt;/code&gt; 와 같이요.&lt;/p&gt;
&lt;h3&gt;1-2. Frontmatter&lt;/h3&gt;
&lt;p&gt;마크다운은 문서의 메타데이터인 Frontmatter 라 불리는 정보를 가지고 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;---
title: &quot;🤔 3. 작성 가이드&quot;
description: &quot;어떻게 글을 작성하고 추가할까요?&quot;
date: 2021-04-03
update: 2021-04-03
tags:
  - hoodie
  - writing-guide
series: &quot;gatsby-starter-hoodie 로 블로그 시작하기&quot;
---&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위는 지금 여러분이 읽고 있는 문서의 Frontmatter 입니다. &lt;code class=&quot;language-text&quot;&gt;title&lt;/code&gt; 과 &lt;code class=&quot;language-text&quot;&gt;date&lt;/code&gt; 는 필수 값입니다. 띄어쓰기를 포함된 문자열을 입력할 때에는 따옴표로 감싸는 것을 추천합니다.&lt;/p&gt;
&lt;h3&gt;1-3. 마크다운 작성하기&lt;/h3&gt;
&lt;p&gt;만약 Frontmatter 까지 작성했다면, 여러분은 그 아래에 마크다운 문서를 작성하면 됩니다. gatsby-starter-hoodie 는 대부분의 마크다운 문법을 지원합니다. 마크다운 작성 방법을 알고 싶다면, Github 의 &lt;a href=&quot;https://guides.github.com/features/mastering-markdown/&quot;&gt;Mastering Markdown&lt;/a&gt; 문서를 참고하세요.&lt;/p&gt;
&lt;h2&gt;2. 코드 하이라이팅 &amp;#x26; Katex&lt;/h2&gt;
&lt;h3&gt;2-1. 코드 하이라이팅&lt;/h3&gt;
&lt;p&gt;Prism.JS 에 기반한 코드 하이라이팅이 제공됩니다.&lt;/p&gt;
&lt;h4&gt;예시&lt;/h4&gt;
&lt;p&gt;Javascript&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Python&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그 외 더 많은 언어를 제공합니다. 제공되는 언어를 확인하고 싶다면, &lt;a href=&quot;https://prismjs.com/&quot;&gt;Prism.js 웹사이트&lt;/a&gt; 를 참고하세요.&lt;/p&gt;
&lt;h3&gt;2-2. Katex&lt;/h3&gt;
&lt;p&gt;Katex 문법을 지원하여 복잡한 수식도 쉽게 표현할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;인라인 모드&lt;/h4&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;E = m c^{2}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.68333em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05764em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2777777777777778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2777777777777778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8141079999999999em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141079999999999em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;블럭 모드&lt;/h4&gt;
&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msubsup&gt;&lt;mo&gt;∫&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∞&lt;/mi&gt;&lt;/msubsup&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\int_{0}^{\infty} f(x) dx&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.326242em;vertical-align:-0.9119499999999999em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;&lt;span class=&quot;mop op-symbol large-op&quot; style=&quot;margin-right:0.44445em;position:relative;top:-0.0011249999999999316em;&quot;&gt;∫&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.414292em;&quot;&gt;&lt;span style=&quot;top:-1.7880500000000001em;margin-left:-0.44445em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.8129000000000004em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∞&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9119499999999999em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.16666666666666666em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;h2&gt;3. 글에 이미지 추가하기&lt;/h2&gt;
&lt;p&gt;상대경로를 이용하여 쉽게 이미지를 추가할 수 있습니다. 디렉토리를 생성하고 그 안에 &lt;code class=&quot;language-text&quot;&gt;index.md&lt;/code&gt; 를 추가하여, 글을 추가하는 방법으로 작성해야 이미지 관리가 쉽습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/69b244095d8c72158c9dd2d4ca59a7b1/aaf92/sample-image.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 61.1764705882353%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQBAgP/xAAVAQEBAAAAAAAAAAAAAAAAAAACAf/aAAwDAQACEAMQAAABUsxAixiE/wD/xAAbEAACAwADAAAAAAAAAAAAAAABAgADBBEiM//aAAgBAQABBQIFOW7ETHWtk0ezWFT/AP/EABURAQEAAAAAAAAAAAAAAAAAABBB/9oACAEDAQE/AYf/xAAXEQADAQAAAAAAAAAAAAAAAAAAAREh/9oACAECAQE/AWsIf//EABkQAAMBAQEAAAAAAAAAAAAAAAABIRECMf/aAAgBAQAGPwJaTWj0fXdaeIkMh//EABoQAQADAQEBAAAAAAAAAAAAAAEAETFRIUH/2gAIAQEAAT8hFdQ6EfUPBjowSgW0YQgXQ9r7FoKHSf/aAAwDAQACAAMAAAAQeN//xAAXEQEAAwAAAAAAAAAAAAAAAAAAAREh/9oACAEDAQE/EJwp/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEh/9oACAECAQE/EIG3/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARITFRQf/aAAgBAQABPxA3pFmq4m2wUjT9WvYy3aVDOTlbQ8O892CBa9ZtcY9TG1n/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;샘플 이미지 캡션&apos; title=&apos;&apos; src=&apos;/static/69b244095d8c72158c9dd2d4ca59a7b1/a22ce/sample-image.jpg&apos; srcset=&apos;/static/69b244095d8c72158c9dd2d4ca59a7b1/0b705/sample-image.jpg 170w,
/static/69b244095d8c72158c9dd2d4ca59a7b1/31389/sample-image.jpg 340w,
/static/69b244095d8c72158c9dd2d4ca59a7b1/a22ce/sample-image.jpg 680w,
/static/69b244095d8c72158c9dd2d4ca59a7b1/29373/sample-image.jpg 1020w,
/static/69b244095d8c72158c9dd2d4ca59a7b1/232dc/sample-image.jpg 1360w,
/static/69b244095d8c72158c9dd2d4ca59a7b1/aaf92/sample-image.jpg 1920w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;샘플 이미지 캡션&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;이미지는 Lazy Loading 으로 로드되어, 빠른 초기 문서 로딩 속도를 확보할 수 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠ 이미지의 모든 확장자는 소문자여야합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;4. 태그&lt;/h2&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/82ce4bec7f5360eef32a473171b181af/6031b/tag-example.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 18.823529411764707%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAEABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB36AH/8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAFRABAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQEAAT8hj//aAAwDAQACAAMAAAAQAA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAVEAEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAQABPxABf//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;tag example&apos; title=&apos;&apos; src=&apos;/static/82ce4bec7f5360eef32a473171b181af/a22ce/tag-example.jpg&apos; srcset=&apos;/static/82ce4bec7f5360eef32a473171b181af/0b705/tag-example.jpg 170w,
/static/82ce4bec7f5360eef32a473171b181af/31389/tag-example.jpg 340w,
/static/82ce4bec7f5360eef32a473171b181af/a22ce/tag-example.jpg 680w,
/static/82ce4bec7f5360eef32a473171b181af/6031b/tag-example.jpg 737w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Frontmatter 의 태그를 통해 쉽게 문서를 분류하고 검색할 수 있습니다. 여러분의 모든 태그는 &lt;code class=&quot;language-text&quot;&gt;https://siteUrl/tags&lt;/code&gt; 경로에서 확인하고, 검색할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;5. 시리즈&lt;/h2&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; margin-bottom: 16px;&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1ea4e56966cb5fb6e110d32124fd883c/d1584/series-example.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 17.058823529411764%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAADABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAdqwSD//xAAVEAEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAQABBQIv/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAFRABAQAAAAAAAAAAAAAAAAAAARD/2gAIAQEAAT8hF//aAAwDAQACAAMAAAAQ8A//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAYEAEAAwEAAAAAAAAAAAAAAAABABAhEf/aAAgBAQABPxAk0GGHCv/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;series example&apos; title=&apos;&apos; src=&apos;/static/1ea4e56966cb5fb6e110d32124fd883c/d1584/series-example.jpg&apos; srcset=&apos;/static/1ea4e56966cb5fb6e110d32124fd883c/0b705/series-example.jpg 170w,
/static/1ea4e56966cb5fb6e110d32124fd883c/31389/series-example.jpg 340w,
/static/1ea4e56966cb5fb6e110d32124fd883c/d1584/series-example.jpg 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;여러분이 연관된 여러개의 문서를 작성할 때 시리즈를 사용할 수 있습니다. Frontmatter 에 작성된 시리즈가 같은 문서끼리 묶여 문서 상단에 리스트로 표시됩니다. 시리즈는 일련의 순서가 있는 문서들을 작성할 때 유용하게 사용할 수 있습니다. 시리즈는 문서의 작성 날짜 순서대로 정렬됩니다.&lt;/p&gt;
&lt;p&gt;현재 문서는 &lt;code class=&quot;language-text&quot;&gt;gatsby-starter-hoodie 로 블로그 시작하기&lt;/code&gt; 라는 시리즈로 설정되어 있습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[🚀 2. 빠르게 시작하기]]></title><description><![CDATA[아래 단계를 따라서 여러분의 블로그를 시작하세요. 굉장히 쉬워요 😉. 1. Gatsby 사이트 생성 컴퓨터에 node.js 와 gatsby-cli 가 설치되어 있어야합니다. 2. 개발 서버 시작 이제 localhost:800…]]></description><link>https://hoonblog.netlify.app/quick-start-kr/</link><guid isPermaLink="false">https://hoonblog.netlify.app/quick-start-kr/</guid><pubDate>Fri, 02 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;아래 단계를 따라서 여러분의 블로그를 시작하세요. 굉장히 쉬워요 😉.&lt;/p&gt;
&lt;h2&gt;1. Gatsby 사이트 생성&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;컴퓨터에 &lt;strong&gt;node.js&lt;/strong&gt; 와 &lt;strong&gt;gatsby-cli&lt;/strong&gt; 가 설치되어 있어야합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ npx gatsby new my-hoodie-blog https://github.com/devHudi/gatsby-starter-hoodie&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;2. 개발 서버 시작&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ cd my-hoodie-blog
$ npm run start&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제 localhost:8000 으로 여러분의 블로그를 접속할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;3. Github 레포지토리 생성&lt;/h2&gt;
&lt;p&gt;Utterance 댓글 위젯은 &lt;strong&gt;Github 이슈 시스템&lt;/strong&gt; 기반입니다. 따라서 각 블로그 별 Github 레포지토리가 필요합니다. 또한 여러분이 Github Pages 혹은 Netlify 로 블로그를 배포하길 원한다면, Github 레포지토리는 필수입니다.&lt;/p&gt;
&lt;p&gt;만약 Github 레포지토리를 생성하는 법을 모른다면, &lt;a href=&quot;https://docs.github.com/en/github/getting-started-with-github/create-a-repo&quot;&gt;Github 공식 문서&lt;/a&gt; 를 참조하세요.&lt;/p&gt;
&lt;h3&gt;원격 레포지토리 등록&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git remote add origin https://github.com/{YOUR_GITHUB_NAME}/{YOUR_REPOSITORY_NAME}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;4. blog-config.js 작성&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MY BLOG&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, This is my blog&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;YOUR NAME&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;siteUrl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://myblog.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://github.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;facebook&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://www.facebook.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;instagram&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://www.instagram.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;etc&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://www.google.com/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;utterances&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{YOUR_GITHUB_NAME}/{YOUR_REPOSITORY_NAME}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pathname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;gatsby-starter-hoodie 는 &lt;code class=&quot;language-text&quot;&gt;blog-config.js&lt;/code&gt; 라는 설정 파일을 제공합니다. 이 파일에서 블로그 정보, 작성자 프로필, Utterance 설정 등을 작성할 수 있습니다. 여러분 블로그 설정에 맞게 &lt;code class=&quot;language-text&quot;&gt;blog-config.js&lt;/code&gt; 를 설정하세요. 하지만, &lt;code class=&quot;language-text&quot;&gt;utterances.type&lt;/code&gt; 속성은 수정하지 않는 것을 권장합니다.&lt;/p&gt;
&lt;h3&gt;프로필 이미지 변경&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;static/profile.png&lt;/code&gt; 에 위치한 이미지 파일을 원하는 이미지 파일로 교체하세요. 만약 파일명을 변경하고 싶다면, &lt;code class=&quot;language-text&quot;&gt;src/components/Bio.jsx&lt;/code&gt; 의 소스코드를 수정해야합니다.&lt;/p&gt;
&lt;h2&gt;5. 포스트 추가&lt;/h2&gt;
&lt;p&gt;마크다운 포스트는 &lt;code class=&quot;language-text&quot;&gt;contents/posts&lt;/code&gt; 경로에 위치해있습니다. 해당 경로에서 글을 작성할 수 있습니다. &lt;a href=&quot;https://devHudi.github.io/gatsby-starter-hoodie/writing-guide&quot;&gt;여기를 클릭하여&lt;/a&gt; 더 자세한 글 작성 방법을 확인하세요.&lt;/p&gt;
&lt;h2&gt;6. 블로그 배포하기&lt;/h2&gt;
&lt;h3&gt;6-1 Netlify 를 통해&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.netlify.com/blog/2016/02/24/a-step-by-step-guide-gatsby-on-netlify/&quot;&gt;A Step-by-Step Guide: Gatsby on Netlify&lt;/a&gt; 문서를 참조하여, Netlify 를 Github 레포지토리와 연결할 수 있습니다. 이 과정은 어렵지 않습니다.&lt;/p&gt;
&lt;p&gt;Github 레포지토리와 연결이 되었다면, Github 레포지토리에 변경사항이 발생할 때 마다 자동으로 여러분의 블로그에 배포됩니다.&lt;/p&gt;
&lt;h3&gt;6-2. Github Pages 를 통해&lt;/h3&gt;
&lt;h4&gt;상황 1&lt;/h4&gt;
&lt;p&gt;레포지토리 이름이 &lt;code class=&quot;language-text&quot;&gt;{YOUR_GITHUB_NAME}.github.io&lt;/code&gt; 형태일 경우, 아래 명령어를 실행해주세요.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ npm run deploy-gh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;상황 2&lt;/h4&gt;
&lt;p&gt;레포지토리 이름이 &lt;code class=&quot;language-text&quot;&gt;{YOUR_GITHUB_NAME}.github.io&lt;/code&gt; 형태가 아닐 경우, 아래 명령어를 실행해주세요.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ npm run deploy-gh-prefix-paths&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;만약 위와 같은 경우 &lt;code class=&quot;language-text&quot;&gt;gatsby-config.js&lt;/code&gt; 에서 &lt;code class=&quot;language-text&quot;&gt;pathPrefix&lt;/code&gt; 를 여러분의 레포지토리 이름으로 바꿔야합니다.&lt;/p&gt;
&lt;h3&gt;6-3. 다른 플랫폼&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ npm run build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 명령어로 Gastby 웹사이트를 빌드할 수 있습니다. 빌드 결과물은 &lt;code class=&quot;language-text&quot;&gt;/public&lt;/code&gt; 에 저장됩니다. &lt;code class=&quot;language-text&quot;&gt;/public&lt;/code&gt; 디렉토리를 여러분이 사용하는 플랫폼의 배포 명령을 통해 배포해주세요.&lt;/p&gt;
&lt;h2&gt;7. 커스터마이징&lt;/h2&gt;
&lt;h3&gt;프로젝트 구조&lt;/h3&gt;
&lt;p&gt;아래 프로젝트 구조를 참고하여 커스터마이징 할 수 있습니다 🙊.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;├── node_modules
├── contents
│   └── posts // your articles are here
├── public // build outputs are here
└── src
    ├── assets
    │   └── theme // theme config is here
    ├── components
    │   └── Article
    │       └── Body
    │           └── StyledMarkdown
    │               └── index.jsx // markdown styles are here
    │   ...
    ├── fonts // webfonts are here
    ├── hooks
    ├── images
    ├── pages // page components are here
    ├── reducers
    ├── templates // post components are here
    └── utils&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[🎇 1. gatsby-starter-hoodie 에 대하여]]></title><description><![CDATA[gatsby-starter-hoodie 에 대하여 gatsby-starter-hoodie 는 기술 블로그를 작성하기 위해 개발된 Gatsby 테마입니다. 마크다운과 많은 프로그래밍 언어의 코드 하이라이팅, 그리고 Katex…]]></description><link>https://hoonblog.netlify.app/about-hoodie-kr/</link><guid isPermaLink="false">https://hoonblog.netlify.app/about-hoodie-kr/</guid><pubDate>Thu, 01 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;gatsby-starter-hoodie 에 대하여&lt;/h2&gt;
&lt;p&gt;gatsby-starter-hoodie 는 기술 블로그를 작성하기 위해 개발된 Gatsby 테마입니다. 마크다운과 많은 프로그래밍 언어의 코드 하이라이팅, 그리고 Katex 문법을 지원합니다. 또한 태그와 시리즈를 통하여 쉽게 게시물을 분류할 수 있습니다.&lt;/p&gt;
&lt;p&gt;다크모드를 지원하는 깔끔한 디자인의 gatsby-starter-hoodie 로 여러분의 블로그를 시작하세요.&lt;/p&gt;
&lt;h2&gt;주요 기능&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;마크다운&lt;/li&gt;
&lt;li&gt;코드 하이라이팅&lt;/li&gt;
&lt;li&gt;Katex 문법&lt;/li&gt;
&lt;li&gt;다크모드 (OS 환경설정과 연동)&lt;/li&gt;
&lt;li&gt;태그 분류&lt;/li&gt;
&lt;li&gt;시리즈 분류&lt;/li&gt;
&lt;li&gt;반응형 웹&lt;/li&gt;
&lt;li&gt;SEO&lt;/li&gt;
&lt;li&gt;Utterance (댓글 위젯)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;시작&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/quick-start-kr&quot;&gt;빠르게 시작하기&lt;/a&gt; 문서에서 블로그를 세팅하세요.&lt;/p&gt;</content:encoded></item></channel></rss>