<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>cosmonumb.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 03 Apr 2025 06:49:18 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>cosmonumb.log</title>
            <url>https://velog.velcdn.com/images/cosmo_numm/profile/145a916c-b3f2-40bc-80dc-8066d5598bd3/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. cosmonumb.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/cosmo_numm" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[커넥티 개발일지 20250403]]></title>
            <link>https://velog.io/@cosmo_numm/%EC%BB%A4%EB%84%A5%ED%8B%B0-%EA%B0%9C%EB%B0%9C%EC%9D%BC%EC%A7%80-20250403</link>
            <guid>https://velog.io/@cosmo_numm/%EC%BB%A4%EB%84%A5%ED%8B%B0-%EA%B0%9C%EB%B0%9C%EC%9D%BC%EC%A7%80-20250403</guid>
            <pubDate>Thu, 03 Apr 2025 06:49:18 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-오늘-개발한-주요-내용-요약">📌 오늘 개발한 주요 내용 요약</h2>
<ul>
<li><p>알림 정보(<code>AlarmArgs</code>)를 별도 클래스로 분리함. </p>
</li>
<li><p>JPA에서 <code>AlarmArgs</code>를 매핑할 때 발생하던 오류(<code>Basic attribute type should not be &#39;AlarmArgs&#39;</code>) 해결</p>
</li>
</ul>
<ol>
<li>알림 데이터를 <strong>JSON 형태로 DB에 저장</strong>할 수 있도록 <code>@Convert</code> + <code>AlarmArgsConverter</code> 적용함. (향후 구조 확장을 고려해 JSON 방식 채택 (확장성과 유연성 확보를 위함임.))</li>
<li><code>AlarmEntity</code>에 <code>@Column(columnDefinition = &quot;json&quot;)</code> 명시하여 DB에서 JSON 타입으로 인식되도록 설정)</li>
</ol>
<hr>
<h2 id="📌-오늘-배운-주요-내용-정리">📌 오늘 배운 주요 내용 정리</h2>
<h3 id="🔸-jpa에서-자바-객체를-db에-저장하는-방법">🔸 JPA에서 자바 객체를 DB에 저장하는 방법:</h3>
<ol>
<li><p><strong><code>@Embeddable</code> + <code>@Embedded</code></strong></p>
<ul>
<li>자바 객체를 컬럼 단위로 DB에 분해해서 저장함.</li>
<li>검색이 쉽고 쿼리 성능이 좋다.</li>
<li>구조가 고정적일 때 적합함. </li>
</ul>
</li>
<li><p><strong><code>@Convert</code> + 커스텀 <code>AttributeConverter</code></strong></p>
<ul>
<li>객체를 JSON 문자열로 직렬화해 하나의 컬럼에 저장한다. </li>
<li>구조가 유동적이고, 변경 가능성이 많을 때 적합하다. </li>
<li>JSON 필드 검색 시 <strong>일반 SQL이 아니라</strong> <code>JSON_EXTRACT</code> 등의 함수를 사용하는게 필요하다. </li>
</ul>
</li>
</ol>
<p>→ 내 프로젝트에서는 알림 정보 구조가 알림 종류에 따라 계속 달라질 수 있어서 JSON 저장 방식이 더 적합하다고 판단했다.</p>
<blockquote>
<h4 id="convert-어노테이션"><code>@Convert</code> 어노테이션</h4>
<p>이 어노테이션은 단순히 <code>@Column(columnDefinition = &quot;json&quot;)</code>만으로는 해결되지 않는 <strong>JPA 매핑 에러를 방지하는 필수 키워드</strong> 이다! 
→ JSON 문자열로 직접 변환/역변환하는 로직을 명확히 지정해줘야 JPA가 오류 없이 작동하기 떄문.</p>
</blockquote>
<hr>
<p>코드를 작성할 때, 설계에서의 관점을 좀 더 비중있게 다뤄야 하는구나. 
JPA와 DB 구조 설계에 있어 &quot;확장성과 유지보수&quot;를 고려하는것에 대한 중요성을 잘 인식해야겠다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Connecti] 추가 기능 목록 - 컨트롤러 테스트 코드 ]]></title>
            <link>https://velog.io/@cosmo_numm/Connecti-%EC%B6%94%EA%B0%80-%EA%B8%B0%EB%8A%A5-%EB%AA%A9%EB%A1%9D-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@cosmo_numm/Connecti-%EC%B6%94%EA%B0%80-%EA%B8%B0%EB%8A%A5-%EB%AA%A9%EB%A1%9D-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C</guid>
            <pubDate>Tue, 04 Feb 2025 07:45:16 GMT</pubDate>
            <description><![CDATA[<h2 id="좋아요-및-댓글-기능-테스트-코드-추가">좋아요 및 댓글 기능 테스트 코드 추가</h2>
<hr>
<h3 id="1-추가할-기능">1. 추가할 기능</h3>
<ul>
<li><strong>좋아요 기능</strong>
사용자가 특정 게시물에 좋아요를 누름
사용자가 이미 좋아요를 눌렀다면 취소됨 (토글 방식)
좋아요 개수를 조회할 수 있음</li>
</ul>
<ul>
<li><strong>댓글 기능</strong>
사용자가 특정 게시물에 댓글을 작성할 수 있음
댓글을 수정할 수 있음
댓글을 삭제할 수 있음
특정 게시물의 모든 댓글을 조회할 수 있음</li>
</ul>
<hr>
<h3 id="2-테스트-코드-추가-순서">2. 테스트 코드 추가 순서</h3>
<ul>
<li><p><strong>좋아요 기능 테스트 코드 작성</strong></p>
<ol>
<li>좋아요 추가/취소 (likePost_Success)</li>
<li>로그인하지 않은 사용자가 좋아요 시도 (likePost_UnauthorizedError)</li>
<li>존재하지 않는 게시물에 좋아요 시도 (likePost_PostNotFoundError)
댓글 기능 테스트 코드 작성</li>
</ol>
</li>
<li><p><strong>댓글 작성 (createComment_Success)</strong></p>
<ol>
<li>로그인하지 않은 사용자가 댓글 작성 시도 (createComment_UnauthorizedError)</li>
<li>존재하지 않는 게시물에 댓글 작성 시도 (createComment_PostNotFoundError)</li>
<li>댓글 수정 (modifyComment_Success)</li>
<li>본인이 아닌 사용자가 댓글 수정 시도 (modifyComment_InvalidPermissionError)</li>
<li>댓글 삭제 (deleteComment_Success)</li>
<li>본인이 아닌 사용자가 댓글 삭제 시도 (deleteComment_InvalidPermissionError)</li>
<li>특정 게시물의 댓글 목록 조회 (getComments_Success)</li>
</ol>
</li>
</ul>
<hr>
<p>테스트 코드에서는 MockBean을 사용해 PostService와 CommentService를 모킹(mocking)하여 실제 데이터베이스 연동 없이 서비스 레이어의 동작을 검증할 예정임.</p>
<p>먼저, 좋아요 기능을 추가하고, 댓글 기능을 추가하는 방식으로 진행함. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[테스트 케이스 작성시 메서드 이름 정하기 ]]></title>
            <link>https://velog.io/@cosmo_numm/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BC%80%EC%9D%B4%EC%8A%A4-%EC%9E%91%EC%84%B1%EC%8B%9C-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%9D%B4%EB%A6%84-%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@cosmo_numm/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BC%80%EC%9D%B4%EC%8A%A4-%EC%9E%91%EC%84%B1%EC%8B%9C-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%9D%B4%EB%A6%84-%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 22 Jan 2025 11:39:38 GMT</pubDate>
            <description><![CDATA[<p>테스트 메서드 이름은 테스트의 목적과 내용을 명확하게 표현해야 가독성이 좋고, 협업 시 다른 개발자들이 쉽게 이해할 수 있다.</p>
<h3 id="이름-수정의-원칙"><strong>이름 수정의 원칙</strong></h3>
<ol>
<li><p><strong>의도 명확히 표현</strong>:
예시)</p>
<ul>
<li><code>shouldReturnFeedListWhenUserIsAuthenticated</code>: 로그인된 사용자가 요청했을 때 피드 목록이 반환된다는 것을 명확히 표현함.</li>
<li><code>shouldReturnUnauthorizedWhenUserIsNotAuthenticated</code>: 비로그인 상태에서 401 상태를 반환하는 경우를 명확히 표현함.</li>
</ul>
</li>
<li><p><strong>테스트 조건과 기대 결과 포함</strong>:</p>
<ul>
<li>메서드 이름에서 테스트 조건(<code>whenUserIsAuthenticated</code>)과 기대 결과(<code>shouldReturnFeedList</code>)를 함께 명시함.</li>
</ul>
</li>
<li><p><strong>일관된 네이밍 패턴 사용</strong>:</p>
<ul>
<li><code>should</code> + <code>동작</code> + <code>조건</code> 형태로 작성하여 가독성을 높임.</li>
</ul>
</li>
</ol>
<hr>
<h3 id="이름-변경-후-기대-효과"><strong>이름 변경 후 기대 효과</strong></h3>
<ul>
<li>메서드 이름만으로 테스트의 목적을 쉽게 이해할 수 있어 유지보수가 용이해짐.</li>
<li>협업 시 다른 개발자들과의 의사소통이 원활해짐.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Connecti] 테스트 작성 순서 관련]]></title>
            <link>https://velog.io/@cosmo_numm/Connecti-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%9E%91%EC%84%B1-%EC%88%9C%EC%84%9C-%EA%B4%80%EB%A0%A8</link>
            <guid>https://velog.io/@cosmo_numm/Connecti-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%9E%91%EC%84%B1-%EC%88%9C%EC%84%9C-%EA%B4%80%EB%A0%A8</guid>
            <pubDate>Tue, 14 Jan 2025 10:31:20 GMT</pubDate>
            <description><![CDATA[<h3 id="현재-커넥티-테스트-진행-과정에서-컨트롤러-테스트를-먼저-작성하고-서비스-테스트를-작성하는-이유">현재 커넥티 테스트 진행 과정에서, 컨트롤러 테스트를 먼저 작성하고 서비스 테스트를 작성하는 이유</h3>
<ol>
<li><p><strong>비즈니스 요구사항을 상위 레벨에서 검증하기 위함.</strong>
컨트롤러 테스트는 애플리케이션의 외부 레이어(HTTP 요청/응답 처리)를 검증하는 역할을 하며, 사용자 요청(HTTP API 호출)이 어떻게 처리되고 어떤 결과를 반환해야 하는지를 상위 레벨에서 설계하고 확인할 수 있음.</p>
<p>-&gt; 이를 통해 비즈니스 요구사항을 상위 레벨에서 정의한 후, 하위 레이어(서비스, 리포지토리)를 구현하는 방식으로 개발할 수 있음.</p>
</li>
<li><p><strong>HTTP 인터페이스 설계를 명확히 하기 위함.</strong>
컨트롤러 테스트를 먼저 작성하면 HTTP 인터페이스(API 설계)가 명확해짐.</p>
<p>-&gt; 어떤 URL로 어떤 HTTP 메서드(POST, GET, PUT, DELETE)를 사용하며, 요청 및 응답 데이터 형식이 어떻게 생겼는지를 컨트롤러 테스트 작성 단계에서 자연스럽게 정의할 수 있음. (외부와의 상호작용 방식을 먼저 확정)</p>
</li>
<li><p><strong>현재 프로젝트에서 상위 레벨부터 하위 레벨로 내려가는 설계 방식을 따르고 있으므로</strong>
컨트롤러 테스트를 먼저 작성하고, 이에 맞는 서비스 테스트 및 로직을 구현하는 방식은 상위 레벨부터 하위 레벨로 내려가는 설계 방식(Top-Down Approach)임.
-&gt; 이 방식은 요구사항 흐름을 따라가기 쉽고, 로직 누락이나 중복을 방지할 수 있다.</p>
</li>
<li><p><strong>초기 단계에서 서비스 레이어가 복잡하지 않을 가능성이 있기 때문.</strong>
초기에 서비스 레이어가 단순하거나 특정 규칙만 처리해야 한다면, 컨트롤러 테스트를 작성하면서 자연스럽게 서비스 레이어를 구현할 수 있다. -&gt; 빠른 개발을 진행할 수 있게 됨.</p>
</li>
</ol>
<p>(결론: 나는 TDD의 초보자이므로 사용자 요청/응답 관점에서 시작하는 것이 더 직관적임.)</p>
<hr>
<h3 id="최근-관점에서의-권장-방식--서비스-테스트를-먼저-작성하는-이유">최근 관점에서의 권장 방식 ~ 서비스 테스트를 먼저 작성하는 이유:</h3>
<ol>
<li><strong>비즈니스 로직 중심 테스트</strong></li>
</ol>
<ul>
<li>서비스 계층은 핵심 비즈니스 로직을 포함하고 있어 가장 중요한 테스트 대상이먀, 컨트롤러는 단순히 요청을 받아 서비스로 전달하는 간단한 역할이 대부분이므로.</li>
</ul>
<ol start="2">
<li><strong>테스트 안정성</strong></li>
</ol>
<ul>
<li>컨트롤러 테스트는 HTTP 요청/응답, 시큐리티 설정 등 외부 요인에 영향을 받기 쉽다! 서비스 테스트는 이러한 외부 의존성이 적어 더 안정적이다.</li>
</ul>
<ol start="3">
<li><strong>개발 효율성</strong></li>
</ol>
<ul>
<li>서비스 테스트를 먼저 작성하면 <strong>비즈니스 요구사항에 집중</strong>할 수 있다. (핵심 로직이 검증된 후 컨트롤러 구현이 더 수월해짐)</li>
</ul>
<blockquote>
<p>즉, 서비스 테스트를 먼저 작성하면:</p>
</blockquote>
<ol>
<li>진짜 중요한 규칙을 먼저 만들고</li>
<li>나중에 API가 바뀌어도 핵심 기능은 안전하며</li>
<li>사용자 입장에서 중요한 기능을 먼저 검증할 수 있다는 장점이 있다.</li>
</ol>
<p>(이러한 접근 방식은 Martin Fowler의 글이나 Clean Architecture(Robert C. Martin)와 같은 현대적인 아키텍처 패턴에서도 강조되고 있음)</p>
<hr>
<blockquote>
<p>현재 진행중인 커넥티 SNS 어플리케이션에서 게시물 작성 기능을 예시로 들어 TDD 접근 방식의 차이를 알아본다. </p>
</blockquote>
<p><strong>1. 컨트롤러 테스트 먼저 작성하는 경우</strong></p>
<pre><code class="language-java">@Test
void 게시물_작성_성공() {
    // given
    PostCreateRequest request = new PostCreateRequest(&quot;제목입니다&quot;, &quot;내용입니다&quot;, List.of(&quot;image1.jpg&quot;));

    // when
    ResponseEntity&lt;PostResponse&gt; response = postController.createPost(request);

    // then
    assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
    assertThat(response.getBody().getId()).isNotNull();
}</code></pre>
<p>이 방식은 HTTP 응답이나 요청 형식에 먼저 집중하게 된다. 실제 중요한 비즈니스 로직은 아직 테스트되지 않은 상태다.</p>
<p><strong>2. 서비스 테스트 먼저 작성하는 경우</strong></p>
<pre><code class="language-java">@Test
void 게시물_작성시_이미지는_최대_5장까지_가능하다() {
    // given
    List&lt;String&gt; tooManyImages = List.of(&quot;1.jpg&quot;, &quot;2.jpg&quot;, &quot;3.jpg&quot;, &quot;4.jpg&quot;, &quot;5.jpg&quot;, &quot;6.jpg&quot;);

    // when &amp; then
    assertThatThrownBy(() -&gt; 
        postService.createPost(&quot;제목&quot;, &quot;내용&quot;, tooManyImages))
        .isInstanceOf(TooManyImagesException.class);
}

@Test
void 게시물_내용은_최대_500자까지_가능하다() {
    // given
    String tooLongContent = &quot;A&quot;.repeat(501);

    // when &amp; then
    assertThatThrownBy(() -&gt; 
        postService.createPost(&quot;제목&quot;, tooLongContent, List.of()))
        .isInstanceOf(ContentTooLongException.class);
}

@Test
void 게시물_작성_성공시_팔로워에게_알림이_발송된다() {
    // given
    String title = &quot;제목&quot;;
    String content = &quot;내용&quot;;
    List&lt;String&gt; images = List.of(&quot;image1.jpg&quot;);

    // when
    Post savedPost = postService.createPost(title, content, images);

    // then
    verify(notificationService).notifyFollowers(savedPost);
    assertThat(savedPost.getTitle()).isEqualTo(title);
    assertThat(savedPost.getContent()).isEqualTo(content);
}</code></pre>
<p>서비스 테스트를 먼저 작성하면 다음과 같은 <strong>비즈니스 규칙</strong>들을 먼저 검증할 수 있다:</p>
<ol>
<li>이미지는 최대 5장까지만 첨부 가능하다</li>
<li>게시물 내용은 500자를 넘을 수 없다</li>
<li>게시물 작성 시 팔로워들에게 알림이 발송되어야 한다</li>
</ol>
<hr>
<h3 id="이렇게-접근하면-경우의-장점">이렇게 접근하면 경우의 장점:</h3>
<ol>
<li>SNS 서비스에서 정말 중요한 <strong>도메인 규칙</strong>들을 먼저 검증할 수 있다</li>
<li>나중에 API 스펙이 바뀌더라도 (예: REST → GraphQL) 핵심 비즈니스 로직은 그대로 유지된다</li>
<li>실제 사용자 시나리오에 더 집중할 수 있다</li>
</ol>
<hr>
<p>(상위 항목 관련 예시 설명 추가)</p>
<p><strong>1. 도메인 규칙 먼저 검증하기</strong></p>
<ul>
<li>인스타그램에서 사진을 10장 올리려고 하면 &quot;최대 5장까지만 가능합니다&quot;라고 뜬다. -&gt; 이것이 <strong>도메인 규칙</strong>임.</li>
<li>컨트롤러 테스트만 작성하면 &quot;응답 코드가 400이 와야 한다&quot;는 것만 테스트하게 된다.</li>
<li>서비스 테스트를 먼저 작성하면 &quot;왜 5장이어야 하는지&quot;, &quot;6장이 들어오면 어떻게 처리해야 하는지&quot; 등 <strong>진짜 중요한 규칙</strong>을 먼저 테스트할 수 있다.</li>
</ul>
<p><strong>2. API 스펙이 바뀌어도 비즈니스 로직 유지</strong></p>
<ul>
<li>음식점으로 비유하면:<ul>
<li>컨트롤러는 &quot;주문을 받는 직원&quot;이다 (배달앱으로 주문받을지, 전화로 받을지, 매장에서 받을지)</li>
<li>서비스는 &quot;요리사&quot;다 (실제로 음식을 만드는 비즈니스 로직)</li>
</ul>
</li>
<li>주문 방식(API)이 바뀌어도 요리(비즈니스 로직)는 그대로다</li>
<li>서비스 테스트를 먼저 하면 &quot;음식이 제대로 만들어지는지&quot;를 먼저 검증할 수 있다</li>
</ul>
<p><strong>3. 실제 사용자 시나리오에 집중</strong></p>
<ul>
<li>컨트롤러 테스트만 하면: &quot;API 호출했을 때 응답이 잘 오는가?&quot;만 확인</li>
<li>서비스 테스트를 먼저 하면: <ul>
<li>&quot;사용자가 게시물을 작성하면 팔로워에게 알림이 가야 한다&quot;</li>
<li>&quot;게시물에 욕설이 있으면 작성이 안 된다&quot;</li>
<li>&quot;해시태그는 최대 10개까지만 가능하다&quot;
등 <strong>실제 사용자가 경험하는 기능</strong>들을 먼저 테스트할 수 있다</li>
</ul>
</li>
</ul>
<hr>
<p>-&gt;그렇지만 &quot;반드시&quot; 따라야 하는 규칙은 아님.
프로젝트의 특성이나 팀의 상황에 따라 컨트롤러 테스트를 먼저 작성하는 것이 더 효율적일 수도 있으며, 특히 <strong>API 스펙이 먼저 확정되어야 하는 경우</strong>라면 컨트롤러 테스트를 먼저 작성하는 것이 유리할 수 있음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI & 프롬프트 엔지니어링] Claude 를 이용한 문서 작성 참고]]></title>
            <link>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-Claude-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%AC%B8%EC%84%9C-%EC%9E%91%EC%84%B1-%EC%B0%B8%EA%B3%A0</link>
            <guid>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-Claude-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%AC%B8%EC%84%9C-%EC%9E%91%EC%84%B1-%EC%B0%B8%EA%B3%A0</guid>
            <pubDate>Mon, 13 Jan 2025 09:27:54 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Claude의 주요 장점을 활용하여 <strong>보고서</strong>, <strong>기획서</strong>, <strong>기술 문서</strong>를 효과적으로 작성하기 위함</p>
</blockquote>
<hr>
<h4 id="1-claude의-특장점-이해">1. <strong>Claude의 특장점 이해</strong></h4>
<ul>
<li><strong>긴 컨텍스트 이해</strong>: 대규모 데이터와 긴 문맥을 빠르게 이해하고 처리 가능  </li>
<li><strong>전문적 문서 작성</strong>: 체계적이고 명확한 문서 작성 지원  </li>
<li><strong>상세한 분석 능력</strong>: 데이터 기반의 논리적 분석 및 결과 도출  </li>
<li><strong>구조화된 결과물 제공</strong>: 요구에 맞는 포맷과 형식으로 결과 제공  </li>
</ul>
<hr>
<h4 id="2-보고서-작성-예시">2. <strong>보고서 작성 예시</strong></h4>
<h4 id="1-비즈니스-보고서-작성"><strong>(1) 비즈니스 보고서 작성</strong></h4>
<ul>
<li><p><strong>요청 예시</strong>:</p>
<pre><code>  AI 도구 도입에 따른 업무 효율성 분석 보고서를 작성해주세요.

  구성:
  1. 현황 분석
  2. 도입 효과
  3. 비용 분석
  4. 향후 계획

  각 섹션은 구체적 데이터와 사례를 포함해주세요.</code></pre></li>
</ul>
<ul>
<li>현황 분석은 <strong>최신 데이터</strong>가 활용됨 </li>
<li>도입 효과를 정량적/정성적으로 구분하여 설명함  </li>
<li>비용 분석은 <strong>명확한 근거 자료</strong>와 함께 제시됨</li>
</ul>
<h4 id="2-기술-문서-작성"><strong>(2) 기술 문서 작성</strong></h4>
<ul>
<li><p><strong>요청 예시</strong>:</p>
<pre><code>  신규 AI 서비스 기술 명세서를 작성해주세요.

  포함 내용:
  - 시스템 아키텍처
  - 주요 기능 명세
  - API 문서
  - 보안 고려사항

  전문적인 용어와 표준 형식을 사용해주세요.</code></pre></li>
</ul>
<ul>
<li><p>기술 용어를 정확하게 사용하며, 필요 시 정의를 제공  </p>
</li>
<li><p>도식화된 아키텍처와 간결한 설명을 함  </p>
</li>
<li><p>사용자의 요청에 따라 보안 고려사항을 자동으로 포함한 문서를 작성하거나, 이미 작성된 문서에서 보안 관련 항목을 추가하거나 개선하도록 요청할 수 있음.</p>
<p><img src="https://velog.velcdn.com/images/cosmo_numm/post/c4ccf9d5-05f0-42e0-8c75-9009037f226f/image.png" alt="">
(웹 애플리케이션 인증 시스템 기술 문서에 대한 도식화된 답변 예시, Mermaid 마크다운으로 지원함.)</p>
</li>
</ul>
<hr>
<h4 id="3-기획서-작성--프로젝트-기획서-작성">(3) <strong>기획서 작성</strong> : 프로젝트 기획서 작성</h4>
<ul>
<li><p><strong>요청 예시</strong>:</p>
<pre><code>  AI 교육 프로그램 기획서를 작성해주세요.

  필수 항목:
  - 프로그램 개요
  - 목표 및 KPI
  - 세부 커리큘럼
  - 소요 예산
  - 기대 효과

  교육 대상은 일반 직장인이며, 8주 과정으로 구성해주세요.</code></pre><ul>
<li>예) <strong>KPI</strong>,<strong>예산</strong>: 측정 가능한 구체적 목표 제시해주며, 항목별 세부 내역과 근거를 제공해준다.   </li>
</ul>
</li>
</ul>
<hr>
<h4 id="4-문서-분석-및-개선-필요-시">(4) <strong>문서 분석 및 개선 필요 시</strong></h4>
<h4 id="문서-리뷰-요청"><strong>문서 리뷰 요청</strong></h4>
<ul>
<li><p><strong>요청 예시</strong>:</p>
<pre><code>  첨부한 마케팅 기획서를 검토하고 다음 관점에서 개선점을 제시해주세요:

  1. 구성의 논리성
  2. 데이터 활용도
  3. 실행 가능성
  4. 예산 적절성

  각 부분별 구체적인 개선 방안도 함께 제시해주세요.</code></pre><ul>
<li>데이터의 시각화가 필요한 경우 해당 내용을 명시해줌.  </li>
<li>실행 가능성과 현실성을 고려한 피드백 제공해준다고 함.</li>
</ul>
</li>
</ul>
<hr>
<h4 id="-5-구조화된-결과물-얻기">** (5) 구조화된 결과물 얻기**</h4>
<ul>
<li><p>요청 형식 예시:</p>
<pre><code>  다음 형식으로 작성해주세요:

  1. 개요
     - 배경
     - 목적
  2. 본문
     - 주요 내용
     - 세부 설명
  3. 결론
     - 요약
     - 제언</code></pre></li>
</ul>
<hr>
<blockquote>
<h4 id="효과적인-요청-방법"><strong>효과적인 요청 방법</strong></h4>
</blockquote>
<ol>
<li><strong>문서 목적 명확히 제시</strong>: 예) 보고서, 기획서, 기술 문서  </li>
<li><strong>대상 독자층 지정</strong>: 예) 경영진, 개발자, 일반 사용자  </li>
<li><strong>형식 및 스타일 명시</strong>: 예) 표준화된 템플릿 제공  </li>
<li><strong>강조점 설정</strong>: 주요 섹션 및 핵심 내용을 중심으로 요청  </li>
</ol>
<hr>
<h4 id="주의해야-할-사항"><strong>주의해야 할 사항</strong></h4>
<ul>
<li>명확한 요구사항을 전달. </li>
<li>단계별로 수정/보완을 요청하기.</li>
<li>형식의 일관성을 유지하기. </li>
<li>핵심 내용 강조해서 전달.  </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI & 프롬프트 엔지니어링] 코드 작성 프롬프트 (코드 작성 최적화) ]]></title>
            <link>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1-%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1-%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Fri, 03 Jan 2025 03:19:12 GMT</pubDate>
            <description><![CDATA[<hr>
<h3 id="1-python-웹-스크래핑-코드-작성">1. Python 웹 스크래핑 코드 작성</h3>
<blockquote>
<h3 id="프롬프트">프롬프트</h3>
<p>Python으로 웹 스크래핑 코드를 작성해주세요.
<strong>조건:</strong></p>
</blockquote>
<ul>
<li>requests, beautifulsoup4 사용</li>
<li>에러 처리 포함</li>
<li>결과를 CSV로 저장</li>
<li>주석 상세히 포함</li>
</ul>
<h3 id="2-코드-디버깅-및-개선">2. 코드 디버깅 및 개선</h3>
<blockquote>
<h3 id="프롬프트-1">프롬프트</h3>
<p>이 코드에서 발생할 수 있는 잠재적 문제점을 분석하고, 개선된 버전을 작성해주세요.</p>
</blockquote>
<h3 id="응답response">응답(Response)</h3>
<p>위의 프롬프트를 입력하니 이미지처럼 응답을 작성하며 디버깅을 진행하는 코드 줄을 보여준다. 코드를 다른 창에서 보여줄 수 있도록 업데이트 되었나 보다. 해당 창에서는 파이썬 코드를 바로 실행할 수도 있게 만들어두었다. 
<img src="https://velog.velcdn.com/images/cosmo_numm/post/ae44ac66-737e-427c-9277-7532af8f201a/image.png" alt=""></p>
<hr>
<h2 id="본-예시에-적용된-구체적인-프롬프트-기법">본 예시에 적용된 구체적인 프롬프트 기법</h2>
<h4 id="1-명확하고-구체적인-프롬프트-작성">1. <strong>명확하고 구체적인 프롬프트 작성</strong></h4>
<ul>
<li><p><strong>조건을 필수적으로 명시:</strong><br>프롬프트에서 <code>requests</code>, <code>beautifulsoup4</code> 사용, 에러 처리, CSV 저장 등 <strong>구체적인 요구사항</strong>을 명시해야함. (조건이 구체적일수록 AI는 더 적절한 코드를 생성함)</p>
<p>→ <strong>프롬프트 예시:</strong><br>&quot;Python으로 웹 스크래핑 코드를 작성해주세요. <code>requests</code>와 <code>beautifulsoup4</code>를 사용하고, 에러 처리를 포함해 결과를 CSV로 저장해주세요.&quot; </p>
</li>
</ul>
<h4 id="2-체계적인-문제-해결-방식을-유도">2. <strong>체계적인 문제 해결 방식을 유도</strong></h4>
<ul>
<li><p><strong>프롬프트의 단계적 요구:</strong> 세부 기능을 단계적으로 요구한다. (AI가 코드를 논리적으로 분리하고, 단계별 접근 방식을 사용하도록 유도한다.) </p>
<p>→ <strong>프롬프트 예시:</strong><br>&quot;Python으로 웹 스크래핑 코드를 작성하고, 네트워크 오류 및 HTTP 오류를 처리해주세요. 결과는 CSV 파일로 저장하고, 각 함수에 주석을 자세히 달아주세요.&quot;</p>
</li>
</ul>
<h4 id="3-컨텍스트를-유지하고-세부적인-요구를-반복">3. <strong>컨텍스트를 유지하고 세부적인 요구를 반복</strong></h4>
<ul>
<li><p><em>이미 작성된 코드를 기반으로</em> <strong>문제점을 분석하고 개선하는 방식</strong>을 사용한다. 
(AI가 기존 코드를 참조하고 연속적으로 수정 및 개선 작업을 수행하도록 한다.)</p>
<p>→ <strong>프롬프트 예시:</strong><br>&quot;위 코드를 기반으로, 발생할 수 있는 문제점을 분석하고 코드 품질을 향상시켜 주세요.&quot;  </p>
</li>
</ul>
<h4 id="4-ai에게-역할을-부여함-persona-기법">4. <strong>AI에게 역할을 부여함 (Persona 기법)</strong></h4>
<ul>
<li>AI에게 <strong>역할을 명시적으로 부여</strong>하면, 전문적이고 신뢰할 수 있는 답변을 얻을 수 있음. 
→ <strong>프롬프트 예시:</strong>  <ul>
<li>&quot;당신은 Python 전문가입니다. Python으로 웹 스크래핑 코드를 작성하고, 발생할 수 있는 에러와 보완책을 설명해주세요.&quot;  </li>
<li>&quot;프로그래밍 강사처럼 코드를 설명하고, 각 단계별로 상세한 주석을 추가해주세요.&quot;  </li>
</ul>
</li>
</ul>
<h4 id="5-에러-처리-및-예외-상황-대응-요구">5. <strong>에러 처리 및 예외 상황 대응 요구</strong></h4>
<ul>
<li><p>프롬프트에 <strong>에러 처리와 예외 상황</strong>을 포함하면, AI가 더 견고한 코드를 생성하도록 유도됨. (에러 핸들링 없이 단순한 스크래핑 코드를 요구하는 경우와 비교해 <strong>코드 안정성이 크게 향상된다.</strong> )</p>
<p>→ <strong>프롬프트 예시:</strong><br> &quot;HTTPError, ConnectionError, Timeout 등 주요 예외를 처리하는 코드를 작성해주세요.&quot;  </p>
</li>
</ul>
<h4 id="6-결과물-평가-및-검증-요청">6. <strong>결과물 평가 및 검증 요청</strong></h4>
<ul>
<li><p>AI에게 코드를 검증하고 예상되는 오류나 문제를 분석하도록 요청</p>
<p>→ <strong>프롬프트 예시:</strong>  </p>
<ul>
<li>&quot;코드 실행 후 데이터가 없는 경우, 경고 메시지를 출력하고 종료하도록 작성해주세요.&quot; </li>
<li>&quot;추출된 데이터가 없는 경우, 사용자에게 경고 메시지를 출력하는 기능을 추가해주세요.&quot;</li>
</ul>
</li>
</ul>
<h4 id="7-프롬프트-반복-및-리팩토링-요청">7. <strong>프롬프트 반복 및 리팩토링 요청</strong></h4>
<ul>
<li><p>첫 번째 코드 생성 이후 응답을 개션하는 방법</p>
<p>→ <strong>프롬프트 예시:</strong>  </p>
<ul>
<li>&quot;코드의 효율성을 높이고 중복 코드를 제거하는 방식으로 리팩토링해주세요.&quot;  </li>
<li>&quot;추출된 데이터가 많아질 경우를 대비해 CSV 저장 방식을 개선하고, 파일이 존재하면 덮어쓰지 않고 추가 저장하도록 수정해주세요.&quot;  </li>
</ul>
</li>
</ul>
<hr>
<h3 id="주의할-사항">주의할 사항!</h3>
<ul>
<li>데이터 정확성 확인</li>
<li>응답 코드에 대한 테스트가 필요함 (결과 검증 필수)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI & 프롬프트 엔지니어링]컨텍스트 활용 ]]></title>
            <link>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Fri, 03 Jan 2025 02:43:21 GMT</pubDate>
            <description><![CDATA[<h2 id="프롬프트-엔지니어링-컨텍스트-활용하기-이전-대화를-참조하여-맥락-유지하기">프롬프트 엔지니어링: 컨텍스트 활용하기 (이전 대화를 참조하여 맥락 유지하기)</h2>
<p>AI와의 상호작용에서 중요한 요소 중 하나는 <strong>컨텍스트(context)</strong>를 효과적으로 활용하는 것이다. 컨텍스트(~맥락)를 잘 사용하면 AI가 사용자의 의도를 더 정확하게 파악하고, 더욱 자연스럽고 일관된 답변을 제공할 수 있다. </p>
<hr>
<h3 id="1-이전-대화-참조하기">1. 이전 대화 참조하기</h3>
<p>AI는 독립적인 질문에 답변하는 것뿐만 아니라, <strong>이전 대화의 내용을 기억하고 참조</strong>할 수 있다. 이를 통해 AI는 대화의 흐름을 이어가며, 연관된 질문에도 일관된 답변을 제공한다.</p>
<p><strong>예시:</strong><br><strong>사용자:</strong> for 문으로 리스트 순회하는 법 알려줘.<br><strong>AI:</strong> Python에서 for 문을 사용해 리스트를 순회하려면 다음과 같이 작성합니다.  </p>
<pre><code class="language-python">fruits = [&#39;apple&#39;, &#39;banana&#39;, &#39;cherry&#39;]
for fruit in fruits:
    print(fruit)</code></pre>
<p><strong>사용자:</strong> 다른 예제도 보여줘.<br><strong>AI:</strong> 다음은 리스트에서 짝수만 출력하는 예제입니다.  </p>
<pre><code class="language-python">numbers = [1, 2, 3, 4, 5, 6]
for number in numbers:
    if number % 2 == 0:
        print(number)</code></pre>
<blockquote>
<p>위 예시에서 AI는 &#39;다른 예제도 보여줘&#39;라는 요청을 받았을 때, 이전 대화에서 &#39;for 문&#39;과 &#39;리스트 순회&#39;를 주제로 다룬 것을 기억하고 관련된 추가 예제를 제공한다.</p>
</blockquote>
<hr>
<h3 id="2-연속된-질문하기">2. 연속된 질문하기</h3>
<p>연속된 질문을 통해 AI는 사용자의 깊이 있는 궁금증을 해결할 수 있다. 초기 질문에서 파생된 후속 질문을 하더라도 AI는 맥락을 유지하며 흐름을 이어간다.</p>
<p><strong>예시:</strong><br><strong>사용자:</strong> 인공지능의 종류에는 무엇이 있어?<br><strong>AI:</strong> 인공지능에는 좁은 인공지능(Narrow AI), 범용 인공지능(General AI), 초지능(Super AI)이 있습니다.<br><strong>사용자:</strong> Narrow AI에 대해 자세히 알려줘.<br><strong>AI:</strong> Narrow AI는 특정 작업에 특화된 인공지능으로, 예를 들어 음성 비서나 이미지 인식 프로그램이 이에 해당합니다.  </p>
<blockquote>
<p>AI는 &#39;인공지능의 종류&#39;라는 초기 질문에서 &#39;Narrow AI&#39;라는 개념을 인식하고, 추가 질문에 대해 구체적으로 설명한다.</p>
</blockquote>
<hr>
<h3 id="3-대화-맥락-유지하기">3. 대화 맥락 유지하기</h3>
<p>대화가 길어질수록 AI가 <strong>대화의 흐름을 기억하고 일관된 정보를 제공</strong>하는 것은 매우 중요하다. 이를 통해 대화가 부자연스럽게 끊기지 않고, 사용자는 AI와의 상호작용에서 더 유용한 경험을 얻을 수 있다.</p>
<p><strong>예시:</strong><br><strong>사용자:</strong> 내일 비가 올까?<br><strong>AI:</strong> 내일은 비 소식이 없습니다.<br><strong>사용자:</strong> 그럼 주말에는 어떨까?<br><strong>AI:</strong> 주말에는 비가 올 가능성이 있습니다. 토요일 오후에 비 예보가 있습니다.  </p>
<blockquote>
<p>&#39;주말에는 어떨까?&#39;라는 질문은 명확하게 날씨를 지칭하지 않는다. 하지만 AI는 이전 질문에서 &#39;날씨&#39;를 주제로 다뤘음을 인식하고 자연스럽게 답변을 이어간다.</p>
</blockquote>
<hr>
<h3 id="주의할-점">주의할 점</h3>
<h4 id="효과적인-사용을-위한-방법"><strong>효과적인 사용을 위한 방법</strong></h4>
<ul>
<li>구체적인 지시어 사용하기</li>
<li>단계별로 질문하기</li>
<li>필요시 부가 설명 추가하기</li>
</ul>
<h4 id="한계점을-이해한다"><strong>한계점을 이해한다</strong></h4>
<ul>
<li>최신 정보가 제한됨</li>
<li>사실 정보의 재확인이 필요함</li>
<li>윤리적 가이드라인을 준수하는지</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI & 프롬프트 엔지니어링]프롬프트 최적화 기법]]></title>
            <link>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%B5%9C%EC%A0%81%ED%99%94-%EA%B8%B0%EB%B2%95</link>
            <guid>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%B5%9C%EC%A0%81%ED%99%94-%EA%B8%B0%EB%B2%95</guid>
            <pubDate>Thu, 02 Jan 2025 09:31:57 GMT</pubDate>
            <description><![CDATA[<h2 id="프롬프트-엔지니어링-최적화-전략">프롬프트 엔지니어링: 최적화 전략</h2>
<p>프롬프트 엔지니어링은 대규모 언어 모델 LLM의 성능을 극대화하는 데 핵심적인 역할을 하며, 명확하고 구조화된 요청을 통해 모델이 원하는 답변을 정확하게 도출할 수 있도록 유도해야 한다. </p>
<p>이 글에서는 대규모 언어 모델(LLM)을 다루는 기술인 프롬프트 엔지니어링의 최적화 기법을 확인하기 위해, 논문 &quot;Principled Instructions Are All You Need for Questioning LLaMA-1/2, GPT-3.5/4&quot;에서 제시된 주요 기법과, LLM의 성능을 극대화하는 방법을 정리했다. </p>
<p>(논문에서는 LLaMA-1/2 및 GPT-3.5, GPT-4와 같은 최신 언어 모델을 대상으로 26가지의 원칙을 적용해 프롬프트를 최적화하는 방법을 제시했다. 이러한 원칙은 정확성 및 응답 품질을 평균 57.7%, 36.4% 향상시켰다.) </p>
<hr>
<h3 id="주요-프롬프트-엔지니어링-전략">주요 프롬프트 엔지니어링 전략</h3>
<ol>
<li><strong>프롬프트 구조 및 명확성</strong>  </li>
</ol>
<ul>
<li>대상 독자 명시: &quot;해당 독자는 이 분야의 전문가입니다&quot;와 같이 명확한 대상 설정  </li>
<li>명령형 문구 사용: &quot;이 작업을 수행하세요&quot;와 같은 명확한 지시어 사용  </li>
</ul>
<ol start="2">
<li><strong>구체성 및 정보</strong>  </li>
</ol>
<ul>
<li>예시 포함: &quot;아래 예시와 같은 방식으로 답변하세요&quot;  </li>
<li>편향 제거: &quot;편향되지 않은 답변을 작성하세요&quot;  </li>
</ul>
<ol start="3">
<li><strong>사용자 상호작용 및 참여 유도</strong>  </li>
</ol>
<ul>
<li>추가 정보 요청: &quot;필요한 경우 질문을 통해 정보를 요청하세요&quot;  </li>
<li>점진적 피드백: &quot;각 단계마다 피드백을 제공하고 개선하세요&quot;  </li>
</ul>
<ol start="4">
<li><strong>콘텐츠 및 언어 스타일</strong>  </li>
</ol>
<ul>
<li>불필요한 공손함 제거: &quot;감사합니다&quot;, &quot;부탁드립니다&quot; 등의 표현 생략  </li>
<li>모델 역할 부여: &quot;당신은 수학 교사입니다&quot;와 같이 모델에 명확한 역할을 부여  </li>
</ul>
<ol start="5">
<li><strong>복잡한 작업 및 코딩 프롬프트</strong>  </li>
</ol>
<ul>
<li>복합 작업 분해: 복잡한 문제를 여러 단계로 나누어 프롬프트 작성  </li>
<li>코드 예제 제공: &quot;아래의 예제 코드를 참조하여 문제를 해결하세요&quot;  </li>
</ul>
<hr>
<h4 id="출처-및-참조">출처 및 참조</h4>
<p>Principled Instructions Are All You Need for Questioning LLaMA-1/2, GPT-3.5/4, Sondos Mahmoud Bsharat, Aidar Myrzakhan, Zhiqiang Shen, 2023. 
<a href="https://arxiv.org/pdf/2312.16171">https://arxiv.org/pdf/2312.16171</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI & 프롬프트 엔지니어링]프롬프트 엔지니어링 기초]]></title>
            <link>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Thu, 02 Jan 2025 09:15:07 GMT</pubDate>
            <description><![CDATA[<h3 id="프롬프트란"><strong>프롬프트란?</strong></h3>
<ul>
<li>AI에게 전달하는 명령/질문/지시문</li>
<li>AI의 출력을 결정하는 핵심 요소</li>
<li>의도 전달을 위한 소통 도구</li>
</ul>
<h3 id="프롬프트-엔지니어링이란"><strong>프롬프트 엔지니어링이란?</strong></h3>
<p>프롬프트 엔지니어링은 <strong>AI 언어 모델(예: GPT-4o)의 성능을 극대화하기 위해 프롬프트(질문이나 명령어)를 설계하고 개선하는 전략과 기법</strong>을 의미함. </p>
<hr>
<p>참고) 오픈AI 에서 제공하는 효과적인 프롬프트 작성 방법 </p>
<blockquote>
<p><strong>역할/ 작업/ 형식/ 제약</strong> 의 단계가 필요함. (OpenAI는 명확하고 구체적인 작업 지시, 콘텍스트 제공, 그리고 원하는 출력 형식의 명시를 통해 AI 모델의 성능을 극대화할 수 있다고 강조함.)</p>
</blockquote>
<p><a href="https://platform.openai.com/docs/guides/prompt-engineering">https://platform.openai.com/docs/guides/prompt-engineering</a></p>
<hr>
<h3 id="문서-주요-내용">문서 주요 내용</h3>
<ol>
<li><p><strong>프롬프트 엔지니어링의 목적</strong>  </p>
<ul>
<li><strong>AI가 더 나은 결과를 생성하도록 돕는 것</strong>  </li>
<li>프롬프트를 어떻게 작성하느냐에 따라 AI의 답변 품질이 달라지기 때문에 <strong>효율적인 프롬프트 작성법을 익히는 것이 중요</strong>하다는 점을 강조한다. </li>
</ul>
</li>
<li><p><strong>해당 문서에서 제시하는 6가지 주요 전략</strong>  </p>
<ul>
<li><p><strong>명확한 지시 작성 (Write clear instructions)</strong>  </p>
<ul>
<li>원하는 답변의 형식, 길이와 난이도를 명확히 요구해야함.   </li>
<li>예: &quot;200자 이내로 요약해줘&quot;  </li>
</ul>
</li>
<li><p><strong>참고 자료를 제공 (Provide reference text)</strong>  </p>
<ul>
<li>AI가 허위 정보를 생성하지 않도록 신뢰할 수 있는 자료를 입력으로 제공함.  </li>
</ul>
</li>
<li><p><strong>복잡한 작업을 단순하게 나누기 (Split complex tasks into subtasks)</strong>  </p>
<ul>
<li>복잡한 요청은 단계별로 나눠서 지시함.</li>
</ul>
</li>
<li><p><strong>Give the model time to think</strong>  </p>
<ul>
<li>논리적으로 단계별 사고를 하도록 유도한다.   </li>
</ul>
</li>
<li><p><strong>외부 도구를 사용 (Use external tools)</strong>  </p>
<ul>
<li>검색 엔진이나 코드 실행기 등 외부 도구와 AI를 결합해 더 나은 결과를 생성하도록 한다. </li>
</ul>
</li>
<li><p><strong>변경 사항을 체계적으로 테스트한다. (Test changes systematically)</strong>  </p>
<ul>
<li>프롬프트를 개선하면서 결과를 비교하고 최적의 방식을 찾아가는 과정을 진행한다.   </li>
</ul>
</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI & 프롬프트 엔지니어링]기초 AI 툴 사용과 기본적 이해 ]]></title>
            <link>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81%EA%B8%B0%EC%B4%88-AI-%ED%88%B4-%EC%82%AC%EC%9A%A9%EA%B3%BC-%EA%B8%B0%EB%B3%B8%EC%A0%81-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@cosmo_numm/AI-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81%EA%B8%B0%EC%B4%88-AI-%ED%88%B4-%EC%82%AC%EC%9A%A9%EA%B3%BC-%EA%B8%B0%EB%B3%B8%EC%A0%81-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Thu, 02 Jan 2025 08:54:45 GMT</pubDate>
            <description><![CDATA[<h2 id="ai-도구-선택을-위한-평가-기준">AI 도구 선택을 위한 평가 기준</h2>
<p>적절한 AI 도구를 선택하기 위해서 고려해야  할 것 </p>
<ul>
<li><strong>목적 적합성</strong>: 수행하고자 하는 작업에 최적화된 도구인지 검토해야 한다. 도구가 해결하고자 하는 문제와 일치하는지) </li>
<li><strong>비용 효율성</strong>: 사용 비용 대비 얻을 수 있는 가치를 평가해야 함.(예산에 맞는 툴 선택) </li>
<li><strong>출력물 품질</strong>: 결과물의 정확성과 완성도를 확인해야 한다.  </li>
<li><blockquote>
<p><strong>도구의 설정을 최적화하거나, 후처리 작업을 추가하는 방법 고려</strong></p>
</blockquote>
</li>
<li><strong>사용 편의성</strong>: 학습 곡선과 인터페이스의 직관성을 고려해야 함. (효율성에 영향을 미치기 때문) </li>
</ul>
<h2 id="활용-전략">활용 전략</h2>
<h3 id="1️⃣-명확한-목적-설정">1️⃣ 명확한 목적 설정</h3>
<ul>
<li>해결하고자 하는 문제를 <strong>명확하게 정의</strong></li>
<li>기대하는 <strong>결과물을 구체화</strong>해야함.</li>
</ul>
<h3 id="2️⃣-도구-조합-활용">2️⃣ 도구 조합 활용</h3>
<ul>
<li>각 도구의 장점을 조합하여 워크플로우를 구성</li>
<li>상호 보완적으로 도구를 활용</li>
</ul>
<h3 id="3️⃣-품질-관리">3️⃣ 품질 관리</h3>
<ul>
<li>결과물의 정확성을 검증해야 한다. -&gt; 직접 서치하고 검증하는 과정이 필요하다.</li>
<li>데이터의 품질을 관리하는 것이 중요하다. 자문을 구하거나, 신뢰할 수 있는 데이터 소스를 사용해야 한다.</li>
<li>지속적인 피드백을 통해 결과물을 개선해야 한다.</li>
</ul>
<h3 id="4️⃣-역량-개발">4️⃣ 역량 개발</h3>
<ul>
<li>AI 도구를 효과적으로 활용하기 위해 지속적인 학습이 필요함.</li>
<li>다양한 도구를 사용해보고 경험을 늘려야 한다.</li>
<li>최신 트렌드와 기술 동향을 파악하는 것이 중요하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[클린코드 스터디]20241226]]></title>
            <link>https://velog.io/@cosmo_numm/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%84%B0%EB%94%9420241226</link>
            <guid>https://velog.io/@cosmo_numm/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%84%B0%EB%94%9420241226</guid>
            <pubDate>Thu, 26 Dec 2024 10:00:52 GMT</pubDate>
            <description><![CDATA[<h3 id="클린코드-3장-함수">클린코드 3장 (함수)</h3>
<hr>
<h3 id="1-함수는-작게-더-작게">1. <strong>함수는 작게, 더 작게</strong></h3>
<ul>
<li><strong>함수는 작아야 한다.</strong>  <ul>
<li>한 눈에 들어올 정도로 짧아야 함.  </li>
<li><strong>5~20줄</strong> 정도가 이상적임.  </li>
</ul>
</li>
<li><strong>함수는 한 가지 일을 해야 한다.</strong>  <ul>
<li><strong>한 가지 작업만 수행</strong>하고, 그것을 <strong>잘</strong> 해야 함.  </li>
<li>여러 작업이 섞이면 읽기 어렵고 유지보수가 힘들어짐.  </li>
</ul>
</li>
</ul>
<hr>
<h3 id="2-함수는-한-단계의-추상화만-수행">2. <strong>함수는 한 단계의 추상화만 수행</strong></h3>
<ul>
<li>함수 내부의 모든 문장은 <strong>동일한 추상화 수준</strong>을 가져야 함.  <ul>
<li>상위 수준의 추상화와 하위 수준의 구현이 섞이면 <strong>읽기 어렵고 수정이 어려워짐.</strong>  </li>
</ul>
</li>
<li>추상화가 섞이면 <strong>새로운 함수로 추출</strong>해야 함.  </li>
</ul>
<hr>
<h3 id="3-함수의-이름은-명확하고-직관적으로">3. <strong>함수의 이름은 명확하고 직관적으로</strong></h3>
<ul>
<li><strong>함수 이름은 동사나 동사구</strong>로 작성해야 함.  <ul>
<li>예: <code>getUser()</code>, <code>calculateTax()</code>, <code>validatePassword()</code>  </li>
</ul>
</li>
<li>이름만으로 <strong>함수가 어떤 일을 하는지 알 수 있도록</strong> 작성해야 함.  <ul>
<li>나쁜 예: <code>process()</code>, <code>doTask()</code>  </li>
<li>좋은 예: <code>sendEmailToUser()</code>  </li>
</ul>
</li>
</ul>
<hr>
<h3 id="4-함수는-적은-수의-인수를-가져야-함">4. <strong>함수는 적은 수의 인수를 가져야 함</strong></h3>
<ul>
<li><strong>최대 3개 이하의 인자</strong>가 이상적임.  <ul>
<li><strong>0~2개가 가장 좋음.</strong>  </li>
<li><strong>3개 이상이면</strong> 파라미터 객체로 묶어서 전달.  </li>
<li>예: <code>createOrder(String userId, String itemId, int quantity)</code> 대신<br><code>createOrder(OrderRequest request)</code> 형태로 단순화 가능.  </li>
</ul>
</li>
</ul>
<hr>
<h3 id="5-부수-효과side-effect를-피하라">5. <strong>부수 효과(side effect)를 피하라</strong></h3>
<ul>
<li>함수는 <strong>입력값을 받아서 출력값을 반환하는 순수 함수</strong> 형태가 이상적임.  </li>
<li>전역 변수 수정, 객체 상태 변경 등 <strong>숨겨진 부수 효과</strong>가 있으면 함수의 동작을 예측하기 어려워짐.  </li>
</ul>
<hr>
<h3 id="6-명령-질의-분리command-query-separation">6. <strong>명령-질의 분리(Command-Query Separation)</strong></h3>
<ul>
<li><strong>질의 함수</strong>: 값을 반환하지만 상태를 변경하지 않음.  <ul>
<li>예: <code>isUserActive()</code>, <code>getBalance()</code>  </li>
</ul>
</li>
<li><strong>명령 함수</strong>: 상태를 변경하지만 값을 반환하지 않음.  <ul>
<li>예: <code>disableUser()</code>, <code>updateProfile()</code>  </li>
</ul>
</li>
<li><strong>명령과 질의를 섞지 말라.</strong>  <ul>
<li>예: <code>checkAndDeleteUser()</code> → 삭제는 명령이고, 확인은 질의이므로 분리해야 함.  </li>
</ul>
</li>
</ul>
<hr>
<h3 id="7-오류-처리도-한-가지-일처럼-보이게-하라">7. <strong>오류 처리도 한 가지 일처럼 보이게 하라</strong></h3>
<ul>
<li><strong><code>try-catch</code> 문은 함수에서 분리</strong>해야 함.  </li>
<li>오류 처리 자체를 <strong>별도 함수</strong>로 작성해 가독성을 높임.  <pre><code class="language-java">try {
    deleteFile(filename);
} catch (Exception e) {
    logError(e);
}</code></pre>
➡️ <code>deleteFileSafely(filename)</code> 형태로 추출 가능.  </li>
</ul>
<hr>
<h3 id="8-함수는-읽기-쉽고-이해하기-쉬워야-한다">8. <strong>함수는 읽기 쉽고 이해하기 쉬워야 한다</strong></h3>
<ul>
<li>코드의 흐름이 <strong>위에서 아래로 자연스럽게</strong> 읽히도록 작성해야 함.  </li>
<li>함수 호출 순서가 논리적인 흐름을 따르도록 작성하는 것이 중요함.  </li>
</ul>
<hr>
<h3 id="정리"><strong>정리</strong></h3>
<ul>
<li>작은 함수, 명확한 이름, 부수 효과 없는 순수 함수가 좋은 코드의 핵심이다.  </li>
<li>함수를 작게 쪼개고, 명확한 책임을 가지도록 설계하는 것이 클린 코드의 핵심 철학이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[클린코드 스터디]20241210]]></title>
            <link>https://velog.io/@cosmo_numm/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C1%EC%9E%A5-%EC%8A%A4%ED%84%B0%EB%94%94-20241210</link>
            <guid>https://velog.io/@cosmo_numm/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C1%EC%9E%A5-%EC%8A%A4%ED%84%B0%EB%94%94-20241210</guid>
            <pubDate>Tue, 10 Dec 2024 04:36:40 GMT</pubDate>
            <description><![CDATA[<h2 id="클린코드-12장-1장-깨끗한-코드-2장-의미-있는-이름">클린코드 1~2장 (1장 깨끗한 코드, 2장 의미 있는 이름)</h2>
<hr>
<h3 id="1장-깨끗한-코드"><strong>1장: 깨끗한 코드</strong></h3>
<ul>
<li><p><strong>코드</strong> : 기계가 이해하고 실행할 수 있도록 작성된 <strong>요구사항의 명세</strong>이자 <strong>언어</strong>이다.<br>-&gt; <strong>엄밀하고 정확하며 상세해야 함</strong> (단순화만이 답이 아님.)
-&gt; 기능의 의도*<em>를 분명히 드러내야 하며, *</em>중복을 피하고 검색하기 쉬워야 함.  </p>
</li>
<li><p><strong>깨끗한 코드의 특징</strong>  </p>
<ol>
<li><strong>검색이 쉽다:</strong> 변수, 메서드, 클래스의 이름이 직관적.  </li>
<li><strong>중복이 없다:</strong> 같은 코드나 기능이 여러 곳에 반복되지 않음.  </li>
<li><strong>명확하다:</strong> 코드를 읽는 것만으로도 의도가 파악되어야 함.  </li>
<li><strong>발음하기 쉬운 이름:</strong> 소통이 쉬워야 함.  </li>
</ol>
</li>
</ul>
<hr>
<h3 id="2장-의미-있는-이름"><strong>2장: 의미 있는 이름</strong></h3>
<ul>
<li><p><strong>클래스 이름은 명사</strong>가 적절 ( <code>User</code>, <code>Order</code>처럼 역할을 표현 )</p>
</li>
<li><p><strong>메서드 이름은 동사나 동사구</strong>로 표현하는게 적절함 (<code>get</code>으로 시작하는 메서드,  <code>calculateTotal</code>, <code>send</code>~ 등, 이들 처럼 동작을 표현한다.) </p>
</li>
<li><p>*<em>일관성을 유지해야함 -&gt; *</em> 같은 의미의 개념에는 일관성있게 같은 단어를 사용해야 함.
( 예를들어,  <code>fetch</code>, <code>get</code>, <code>retrieve</code> 중 하나만 사용하는것이 좋다. 
마찬가지로, 같은 동작을 하는 개념에는 같은 단어를 일관성있게 사용해야한다. (동일 코드 기반에 controller, manager, driver 를 혼재해서 쓴다면 안되겠지?)  </p>
</li>
</ul>
<ul>
<li><p>인코딩을 피하라 ( 변수나 클래스 이름에 불필요한 정보를 붙이는 것을 의미.)  </p>
<ol>
<li><p><strong>헝가리식 표기법</strong><br>변수 이름에 데이터 타입을 붙이는 방식임.<br>예: <code>strName</code>, <code>iCount</code><br>➡️ IDE가 타입을 알려주니 더는 필요하지 않음.  </p>
</li>
<li><p><strong>멤버 변수 접두어</strong><br>변수 이름 앞에 <code>_</code>나 <code>m_</code>을 붙이는 방식임.<br>예: <code>_userName</code>, <code>m_password</code><br>➡️ 읽기 어렵고 비일관적임.  </p>
</li>
<li><p><strong>인터페이스와 구현 클래스 구분</strong><br>인터페이스 이름에 <code>I</code>를 붙이거나, 구현 클래스에 <code>Impl</code>을 붙이는 방식. 
<strong>좋은 예:</strong> <code>UserService</code>, <code>UserServiceDefault</code> </p>
<p>-&gt; <strong>불필요한 정보는 빼고, 이름만으로 의도를 명확히 드러내야 한다.</strong></p>
</li>
</ol>
</li>
</ul>
<blockquote>
<p><strong>인터페이스와 구현 클래스 구분</strong> 에 관한 의문점: 현재 진행하고 있는 커넥티 개인 프로젝트에서는 하위 구현 클래스 이름으로 <code>UserServiceImpl</code>을 사용하고 있다. </p>
</blockquote>
<p>이 부분이 걸리는데,  <strong>클린코드</strong>의 관점에서는 <code>Impl</code> 같은 이름이 클래스의 역할이나 의도를 명확히 드러내지 못한다고 보는 것으로 보인다. </p>
<p>이것을 클린코드의 관점에서 개선하려면, <strong>역할을 명확히 표현</strong> 해야하고,  클래스 이름만 보고도 어떤 구현인지 알 수 있도록 이름을 지어야 하는 것일까? 스프링에서는 <code>Impl</code>을 관용적으로 사용하는 경우가 많은 것으로 알고있다.</p>
<p>의미를 더 드러낼 수 있는 이름으로 리팩토링하면 가독성이 좋아지려나? 
 -&gt; 지금 사용하는 <code>UserServiceImpl</code>가 스프링 환경에서는 흔히 쓰이는 방식이 아닌가? 개선이 필요한 것인가?</p>
<hr>
<h4 id="기타--이름-짓기에서-고려할-추가-사항"><strong>기타 : 이름 짓기에서 고려할 추가 사항</strong></h4>
<ol>
<li><p><strong>문제 영역/ 해법 영역의 구분</strong>  </p>
<ul>
<li><strong>문제 영역:</strong> 현실 세계의 개념에 집중.  <ul>
<li>예: <code>User</code>, <code>Address</code>, <code>Order</code>  </li>
</ul>
</li>
<li><strong>해법 영역:</strong> 기술적 구조에 맞는 이름 사용.  <ul>
<li>예: <code>UserController</code>, <code>OrderRepository</code>, <code>AddressValidator</code>  1. <strong>해법 영역과 문제 영역의 개념 구분</strong>  </li>
</ul>
</li>
<li><strong>문제 영역:</strong> 실제로 해결하려는 문제나 도메인과 관련된 개념임.<br>예: <strong>User, Order, Product</strong> (현실 세계에서 사용하는 용어)</li>
<li><strong>해법 영역:</strong> 프로그래머들이 익숙한 기술적 용어를 의미함.<br>예: <strong>Controller, Service, Repository</strong> (애플리케이션 구조나 구현을 위한 용어)<br>➡️ <strong>구분해서 사용해야 함:</strong>  <ul>
<li>도메인 관련 코드는 <strong>문제 영역</strong>의 용어를 사용해야 직관적임.<br>예: User, Address  </li>
<li>구현 관련 코드는 <strong>해법 영역</strong> 용어를 사용해 역할을 명확히 해야 함.<br>예: UserRepository, AddressValidator</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>맥락을 명확하게 개선하기</strong>  </p>
<ul>
<li>이름만으로도 역할과 의도가 명확해야 함. </li>
<li>접두어를 적합하게 사용해야함 
접두어를 사용할 때는 <strong>맥락을 명확히 하기 위해 의미 있는 용어를 선택</strong>해야 함.  </li>
<li><strong>나쁜 예:</strong> FirstName (어떤 맥락의 이름인지 불분명)  </li>
<li><strong>좋은 예:</strong> addrFirstName (주소와 관련된 이름임을 명확히 표현)<br>➡️ 하지만 접두어 사용은 너무 길거나 중복되지 않도록 간결하게 유지하는  <ul>
<li><strong>좋은 예:</strong> <code>addrFirstName</code> (주소와 관련된 이름임을 명시)   </li>
<li><strong>나쁜 예:</strong> <code>FirstName</code> (맥락이 불분명)  </li>
</ul>
</li>
</ul>
</li>
<li><p><strong>불필요한 맥락을 추가하지 않도록 주의하기</strong>  </p>
<ul>
<li><strong>나쁜 예:</strong> <code>AccountAddressStreet</code>  </li>
<li><strong>좋은 예:</strong> <code>Street</code> (이미 <code>Address</code> 객체 안에 포함된 변수라면 충분함)  </li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드 리팩토링 ~ Interface와 DI를 중심으로 한 객체지향 설계]]></title>
            <link>https://velog.io/@cosmo_numm/%EC%BD%94%EB%93%9C-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-Interface%EC%99%80-DI%EB%A5%BC-%EC%A4%91%EC%8B%AC%EC%9C%BC%EB%A1%9C-%ED%95%9C-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84</link>
            <guid>https://velog.io/@cosmo_numm/%EC%BD%94%EB%93%9C-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-Interface%EC%99%80-DI%EB%A5%BC-%EC%A4%91%EC%8B%AC%EC%9C%BC%EB%A1%9C-%ED%95%9C-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84</guid>
            <pubDate>Mon, 02 Dec 2024 11:12:06 GMT</pubDate>
            <description><![CDATA[<p>테스트 코드 예시를 찾아보둔 중, 어쩌다 백기선님이 스프링 관련 언급을 하신 유투브 영상을 보게 되었고, 해당 내용을 정리해두면 좋을 것으로 보여 기록한다. 이제까지 스프링을 목적성 없이 받아들인 부분이 많다는 생각이 든다. </p>
<p><img src="https://velog.velcdn.com/images/cosmo_numm/post/abf2fe15-5398-4205-9c6a-c7bc9046b6e2/image.png" alt="">
테스트코드를 만들기에 장벽이 있던 리팩토링 필요한 코드 예시</p>
<p><img src="https://velog.velcdn.com/images/cosmo_numm/post/d05e204e-bc66-4f26-aabd-1ddaf6f1c46a/image.png" alt="">
리팩토링 후, 테스트코드를 만들기 쉬워짐 </p>
<hr>
<h4 id="1-코드-분석-interface와-di의-역할">1. <strong>코드 분석: Interface와 DI의 역할</strong></h4>
<ul>
<li><p><strong>코드 스크린샷 설명</strong>:</p>
<ul>
<li><code>GitHubService</code>는 Interface로 정의되어 있고, 이를 구현한 <code>DefaultGitHubService</code>는 실제 GitHub API와 통신하는 역할을 한다.</li>
<li><code>RepositoryRank</code>는 <code>GitHubService</code>를 생성하지 않고, DI(Dependency Injection)를 통해 외부에서 주입받아 사용한다.</li>
<li><code>getPoint</code> 메서드는 주입받은 <code>GitHubService</code>를 이용해 GitHub 저장소의 정보를 조회하고, 특정 점수를 계산한다.</li>
</ul>
</li>
<li><p><strong>이 설계의 핵심</strong>:</p>
<ol>
<li><code>RepositoryRank</code>는 구체적인 구현체(<code>DefaultGitHubService</code>)가 아닌 역할(Interface)만 알기 때문에 <strong>강한 결합을 피하고 유연성을 높임</strong>.</li>
<li>테스트 시에는 실제 <code>GitHubService</code> 대신 Mock 객체를 주입하여 외부 종속성을 제거하고 로직 테스트를 가능하게 함.</li>
</ol>
</li>
</ul>
<hr>
<h4 id="2-interface와-di의-필요성">2. <strong>Interface와 DI의 필요성</strong></h4>
<ul>
<li><p><strong>Interface 사용 이유</strong>:</p>
<ol>
<li><strong>구현체 교체 용이성</strong>:<ul>
<li><code>GitHubService</code> 인터페이스를 사용하면, BitBucket이나 GitLab 등 다른 API로 확장할 때 <code>RepositoryRank</code>를 수정할 필요 없이 새로운 구현체만 추가하면 됨.</li>
</ul>
</li>
<li><strong>테스트 용이성</strong>:<ul>
<li>Mock 객체를 사용해 <code>GitHubService</code>의 동작을 시뮬레이션할 수 있음.</li>
</ul>
</li>
</ol>
</li>
<li><p><strong>DI(Dependency Injection)의 역할</strong>:</p>
<ol>
<li><strong>코드의 책임 분리</strong>:<ul>
<li><code>RepositoryRank</code>는 <code>GitHubService</code>를 직접 생성하지 않고 외부에서 주입받기 때문에 자신의 역할(점수 계산 로직)에만 집중할 수 있음.</li>
</ul>
</li>
<li><strong>테스트 유연성</strong>:<ul>
<li>DI를 통해 Mock 객체를 주입받아 실제 GitHub API를 호출하지 않고도 테스트 가능.</li>
</ul>
</li>
</ol>
</li>
</ul>
<hr>
<h4 id="3-구체적인-예시-interface와-di가-없을-때의-문제점">3. <strong>구체적인 예시: Interface와 DI가 없을 때의 문제점</strong></h4>
<ul>
<li><p>Interface와 DI 없이 <code>RepositoryRank</code>가 <code>GitHub</code> 객체를 직접 생성하고 사용하는 경우:</p>
<pre><code class="language-java">public class RepositoryRank {
    private GitHub gitHub = new GitHub();

    public int getPoint(String repositoryName) throws IOException {
        GHRepository repository = gitHub.getRepository(repositoryName);
        // ...
    }
}</code></pre>
</li>
<li><p><strong>문제점</strong>:</p>
<ol>
<li><code>RepositoryRank</code>가 <code>GitHub</code> 객체에 강하게 결합되어 있어 구현체 교체가 어렵다.</li>
<li>테스트 시 실제 GitHub API를 호출해야 하므로 네트워크 환경이나 API 상태에 따라 테스트 결과가 달라질 수 있다.</li>
<li>BitBucket 등 다른 API를 추가하려면 기존 코드를 수정해야 하므로 OCP(Open-Closed Principle)를 위반한다.</li>
</ol>
</li>
</ul>
<hr>
<h4 id="4-구체적인-예시-interface와-di를-사용한-설계의-장점">4. <strong>구체적인 예시: Interface와 DI를 사용한 설계의 장점</strong></h4>
<ul>
<li><p>Interface와 DI를 활용한 현재 설계:</p>
<pre><code class="language-java">public class RepositoryRank {
    private GitHubService gitHubService;

    public RepositoryRank(GitHubService gitHubService) {
        this.gitHubService = gitHubService;
    }

    public int getPoint(String repositoryName) throws IOException {
        GitHub gitHub = gitHubService.connect();
        GHRepository repository = gitHub.getRepository(repositoryName);
        // ...
    }
}</code></pre>
</li>
<li><p><strong>장점</strong>:</p>
<ol>
<li><strong>유연한 구성</strong>: <code>GitHubService</code> 구현체를 교체하거나 확장할 때 <code>RepositoryRank</code>를 수정할 필요가 없다.</li>
<li><strong>테스트 가능성</strong>: Mock 객체를 주입받아 외부 종속성을 제거한 상태에서 로직 테스트 가능.</li>
<li><strong>확장성</strong>: BitBucket, GitLab 등 다른 서비스에 대한 구현체를 추가하고 DI를 통해 주입하면 쉽게 확장 가능.</li>
</ol>
</li>
</ul>
<hr>
<h4 id="5-이-설계의-객체지향-원칙-준수">5. <strong>이 설계의 객체지향 원칙 준수</strong></h4>
<ul>
<li><strong>SRP(단일 책임 원칙)</strong>:<ul>
<li><code>RepositoryRank</code>는 점수 계산이라는 자신의 주된 역할에만 집중하고, 외부 API 호출 방식은 <code>GitHubService</code>에 위임한다.</li>
</ul>
</li>
<li><strong>OCP(개방-폐쇄 원칙)</strong>:<ul>
<li><code>GitHubService</code> 구현체를 교체하거나 추가할 때 기존 코드를 수정할 필요 없이 확장이 가능하다.</li>
</ul>
</li>
<li><strong>DIP(의존성 역전 원칙)</strong>:<ul>
<li><code>RepositoryRank</code>는 구체적인 구현체가 아닌 추상화된 <code>GitHubService</code> 인터페이스에 의존한다.</li>
</ul>
</li>
</ul>
<hr>
<h4 id="6-tdd테스트-주도-개발와의-연결">6. <strong>TDD(테스트 주도 개발)와의 연결</strong></h4>
<ul>
<li><p><strong>Interface와 DI의 역할</strong>:</p>
<ul>
<li>Mock 객체를 사용해 테스트를 독립적으로 수행할 수 있다.</li>
<li>외부 의존성을 제거하여 테스트 속도와 안정성을 확보한다.</li>
</ul>
</li>
<li><p><strong>TDD의 본질</strong>:</p>
<ul>
<li>이러한 설계는 테스트 가능성을 높이고, TDD 방식으로 개발할 때 변경에 강한 구조를 제공한다.</li>
</ul>
</li>
</ul>
<hr>
<h4 id="7-스프링과의-연결-di-컨테이너-활용">7. <strong>스프링과의 연결: DI 컨테이너 활용</strong></h4>
<ul>
<li><strong>DI 컨테이너의 역할</strong>:<ul>
<li>스프링의 DI 컨테이너가 <code>GitHubService</code> 구현체를 생성하고 <code>RepositoryRank</code>에 주입함으로써 DI를 자동으로 처리한다.</li>
</ul>
</li>
<li><strong>스프링 빈 등록</strong>:<ul>
<li><code>@Component</code>, <code>@Bean</code> 등을 사용해 <code>GitHubService</code> 구현체를 스프링 컨테이너에 등록하고 관리할 수 있다.</li>
</ul>
</li>
<li><strong>테스트 시 Mock 주입</strong>:<ul>
<li><code>@MockBean</code>을 사용해 테스트 환경에서 Mock 객체를 주입받아 테스트를 수행할 수 있다.</li>
</ul>
</li>
</ul>
<hr>
<h4 id="8-이-내용이-스프링-학습에-중요한-이유">8. <strong>이 내용이 스프링 학습에 중요한 이유</strong></h4>
<ul>
<li>스프링은 DI를 기반으로 한 프레임워크로, DI와 Interface를 적절히 사용하는 것이 스프링의 핵심이다.</li>
<li>이 예시는 스프링의 철학인 <strong>&quot;구성(configuration)과 사용의 분리&quot;</strong>를 잘 보여준다.</li>
<li>스프링을 제대로 활용하려면 Interface와 DI의 원리와 이점, 그리고 객체지향 설계 원칙을 이해하는 것이 필수적이다.</li>
</ul>
<hr>
<h3 id=""></h3>
<blockquote>
<p>Interface와 DI를 사용한 설계는 객체지향 원칙을 준수하며, 테스트 가능성과 확장성을 극대화한다. 
이 설계를 이해하고 적용하는 것은 스프링 프레임워크의 핵심 철학을 이해하고 활용하는데에 필수적이다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[인조식별자와 인덱스, INDEX SPLIT]]></title>
            <link>https://velog.io/@cosmo_numm/%EC%9D%B8%EC%A1%B0%EC%8B%9D%EB%B3%84%EC%9E%90%EC%99%80-%EC%9D%B8%EB%8D%B1%EC%8A%A4-INDEX-SPLIT</link>
            <guid>https://velog.io/@cosmo_numm/%EC%9D%B8%EC%A1%B0%EC%8B%9D%EB%B3%84%EC%9E%90%EC%99%80-%EC%9D%B8%EB%8D%B1%EC%8A%A4-INDEX-SPLIT</guid>
            <pubDate>Fri, 15 Nov 2024 06:47:02 GMT</pubDate>
            <description><![CDATA[<ol>
<li><h3 id="인조식별자artificial-identifier-">인조식별자(Artificial Identifier) :</h3>
<ul>
<li><strong>인조식별자</strong>란 테이블의 각 행을 고유하게 식별하기 위해 <strong>인위적으로 생성된 키</strong>를 의미한다. </li>
<li>예를 들어, <code>고객 ID</code>를 자동 증가하는 숫자로 부여하는 것이 대표적인 인조식별자 방식이다.</li>
<li>인조식별자는 복잡한 자연식별자(자연키) 대신, 간단하고 관리하기 쉬운 형태의 키(고유식별자)를 사용하고자 할 때 주로 사용된다.</li>
</ul>
</li>
<li><h3 id="인덱스index의-역할과-필요성">인덱스(Index)의 역할과 필요성</h3>
<ul>
<li>데이터베이스에서 <strong>인덱스</strong>는 빠른 검색을 위해 사용하는 <strong>자료구조</strong>다.</li>
<li>예를 들어, 책의 목차처럼 특정 데이터를 찾기 쉽게 만드는 기능이다.</li>
<li>테이블의 특정 컬럼에 인덱스를 생성하면, 검색 성능이 크게 향상된다. 따라서 데이터를 <strong>빠르게 조회하고 싶은 컬럼</strong>에 인덱스를 적용한다. </li>
</ul>
</li>
</ol>
<ol start="3">
<li><h3 id="인덱스와-dml-작업의-상관관계-인덱스가-dml에-취약한-이유">인덱스와 DML 작업의 상관관계: 인덱스가 DML에 취약한 이유</h3>
<ul>
<li>여기서 DML(Data Manipulation Language)은 데이터를 조작하는 작업(쓰기 작업)을 의미하며, <code>INSERT</code>, <code>UPDATE</code>, <code>DELETE</code> 명령어가 포함된다.</li>
<li><strong>인덱스는 검색 속도에 이점</strong>이 있지만, 반대로 <strong>DML 작업에는 부담</strong>이 될 수 있다.<ul>
<li>인덱스를 생성하면, 데이터 삽입, 수정, 삭제 시 인덱스까지 함께 갱신해야 하기 때문이다.</li>
<li>특히, 인덱스가 많을수록 갱신해야 할 인덱스가 많아지면서 작업 속도가 느려진다.</li>
</ul>
</li>
<li>따라서 <strong>인덱스는 읽기 작업(SELECT)</strong>에는 도움이 되지만, <strong>쓰기 작업(DML)</strong>에는 성능 저하의 원인이 될 수 있어 <strong>균형 잡힌 설계</strong>가 필요하다.</li>
</ul>
<blockquote>
<p>결과적으로 , <strong>인덱스</strong>는 검색 성능을 높여주지만, <strong>DML(DML(Data Manipulation Language) 작업이 많아지면 인덱스를 갱신하는 작업이 성능 저하</strong>로 이어질 수 있다.</p>
</blockquote>
</li>
</ol>
<ol start="4">
<li><h3 id="인덱스-스플릿index-split-현상-dml-작업-시특히-데이터-삽입이--잦은-경우-발생하는-문제">인덱스 스플릿(Index Split) 현상: DML 작업 시(특히 데이터 삽입이  잦은 경우) 발생하는 문제</h3>
</li>
</ol>
<ul>
<li><p><strong>인덱스 스플릿</strong> : 인덱스 페이지가 가득 찬 상태에서 새로운 데이터를 중간에 삽입해야 할 때 발생하는 <strong>인덱스 페이지 분할 현상</strong>, 인덱스가 자주 갱신되거나 중간 삽입이 빈번한 환경에서는 이 스플릿 현상이 빈번해짐.</p>
</li>
<li><p>예를 들어, 순서가 정해진 인덱스에 중간 위치에 새로운 값을 넣어야 하는 상황에서 기존 페이지에 공간이 부족할 경우, 인덱스 페이지를 두 개로 나누어 데이터를 재배치하게 된다.
 이로 인해 <strong>데이터 재배치와 새 페이지 생성 작업이 추가로 발생</strong>하여 성능 저하를 일으킨다.</p>
</li>
</ul>
<hr>
<p><strong>인덱스 페이지를 나눈다</strong>?</p>
<p> 인덱스는 데이터를 효율적으로 검색하기 위해 만들어진 <strong>특정한 자료 구조</strong> 이며, 이 자료 구조는 <strong>여러 개의 페이지</strong>로 나뉘어 데이터를 저장한다. &#39;페이지&#39;란 <strong>데이터베이스가 데이터를 저장하는 기본 단위</strong>로, 특정 크기의 데이터 묶음이다.</p>
<h3 id="인덱스-스플릿index-split-현상-발생의-흐름">인덱스 스플릿(Index Split) 현상 발생의 흐름</h3>
<ol>
<li><p>인덱스는 <strong>정렬된 순서</strong>로 데이터를 저장해 둔다. 예를 들어, 숫자 순서로 데이터를 정렬한다고 하면 10, 20, 30, 40, 50 같은 순서로 인덱스 페이지에 저장된다.</p>
</li>
<li><p>인덱스 페이지는 한정된 공간을 가지고 있으므로, 한 페이지에 저장할 수 있는 데이터의 양이 <strong>정해져 있다</strong>. 페이지가 꽉 차면 새로운 데이터를 그 페이지에 추가할 수 없게 된다.</p>
</li>
<li><p>예를 들어, 인덱스가 <strong>10, 20, 30, 40</strong>으로 차 있는데 중간에 <strong>25라는 값을 추가해야 한다면</strong> 문제가 생기며, 이미 페이지가 꽉 차 있으므로 더 이상 데이터를 넣을 공간이 없게 된다.</p>
</li>
<li><p>이럴 때 데이터베이스는 <strong>인덱스 페이지를 두 개로 나눠서(스플릿)</strong> 데이터를 재배치한다.</p>
<ul>
<li>예를 들어, 기존 페이지를 두 개로 나누고, <strong>한 페이지에는 10, 20을</strong> 넣고, <strong>다른 페이지에는 25, 30, 40을</strong> 넣는 방식으로 데이터를 재구성하게 된다.</li>
</ul>
</li>
<li><p>이렇게 되면 <strong>새로운 페이지가 추가되고, 기존 데이터가 재배치되면서</strong> 더 많은 공간을 확보하게 되며, 이 과정에서 <strong>추가적인 작업과 시간이 필요</strong>하기 때문에 성능 저하가 발생할 수 있다. (성능 저하가 발생하는 이유는, 페이지가 나뉘게 되묜서 <strong>새로운 페이지 생성과 데이터 이동 작업</strong>을 필요로 하기 때문에, <strong>추가적인 자원과 시간이 소요</strong>되기 때문이다. </p>
</li>
</ol>
<ul>
<li>데이터가 자주 삽입되거나 인덱스가 자주 변경되는 경우에는 이 스플릿 현상이 자주 발생하여 <strong>전체 시스템의 성능에 부정적인 영향을 줄 수</strong> 있다.
( 예를 들어, <strong>날짜가 순차적으로 증가하는 주문 테이블</strong>이 있고, <code>주문일</code> 컬럼에 인덱스를 걸면, 새로운 주문이 들어올 때마다 <strong>날짜가 인덱스의 끝부분에 추가</strong>되므로 <strong>중간에 삽입이 발생하지 않아 인덱스 스플릿이 거의 일어나지 않는다</strong>.)
하지만, <strong>무작위로 생성되는 고객 ID</strong> 컬럼에 인덱스를 걸면 새로운 데이터가 중간에 삽입될 가능성이 높아 <strong>인덱스 스플릿이 빈번히 발생</strong>하여 성능 저하를 초래할 수 있다.)</li>
</ul>
<blockquote>
<p>그러므로,  인덱스를 설계할 때는 <strong>삽입이 자주 일어나는 컬럼</strong>에 대해 신중하게 고려하고, 인덱스 스플릿 현상이 성능에 미치는 영향을 최소화할 수 있도록 <strong>효율적인 인덱스 설계 (삽입이 자주 일어나는 컬럼에 인덱스를 적용할 때, **인덱스 스플릿이 최소화될 수 있도록 설계</strong>하도록 하는 설계)**가 필요하다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[집계함수에서의 NULL 값 처리]]></title>
            <link>https://velog.io/@cosmo_numm/%EC%A7%91%EA%B3%84%ED%95%A8%EC%88%98%EC%97%90%EC%84%9C%EC%9D%98-NULL-%EA%B0%92-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@cosmo_numm/%EC%A7%91%EA%B3%84%ED%95%A8%EC%88%98%EC%97%90%EC%84%9C%EC%9D%98-NULL-%EA%B0%92-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Fri, 15 Nov 2024 06:33:40 GMT</pubDate>
            <description><![CDATA[<p><strong>집계 함수(Aggregate Function)</strong>에서는 <strong><code>NULL</code> 값을 무시한다</strong></p>
<p> 이 말은, 집계 함수가 데이터를 계산할 때 <strong><code>NULL</code> 값을 계산 대상에 포함하지 않고 계산한다는 것</strong>을 의미한다. 쉽게 말해, 집계 함수는 <code>NULL</code>을 데이터가 없는 것으로 간주하고 제외한 후 결과를 계산한다.</p>
<p>따라서 <code>NULL</code> 값을 처리할 때는 집계 결과에 영향을 미치지 않으니, 필요에 따라 <code>COALESCE</code> 함수 등을 사용해 <code>NULL</code>을 다른 값으로 대체하는 방식을 사용할 수도 있다.</p>
<h3 id="주요-집계-함수와-null-처리-방식">주요 집계 함수와 <code>NULL</code> 처리 방식</h3>
<ol>
<li><p><strong><code>SUM</code> (합계)</strong>  </p>
<ul>
<li><code>NULL</code> 값을 무시하고 나머지 숫자 값만 합산한다.  </li>
<li>예: <code>SUM(값)</code>은 <code>NULL</code>을 포함하지 않은 값들만 더한 결과를 반환한다.</li>
</ul>
</li>
<li><p><strong><code>AVG</code> (평균)</strong>  </p>
<ul>
<li><code>NULL</code> 값을 제외한 나머지 숫자 값의 평균을 계산한다.  </li>
<li>계산 공식: <code>AVG = (합계 / NULL이 아닌 값의 개수)</code>  </li>
<li>예: <code>NULL</code>이 있더라도 나머지 값들로만 평균을 구한다.</li>
</ul>
</li>
<li><p><strong><code>COUNT</code> (개수)</strong>  </p>
<ul>
<li><code>COUNT(*)</code>: <code>NULL</code>을 포함한 전체 행의 개수를 반환한다.  </li>
<li><code>COUNT(컬럼)</code>: 해당 컬럼에서 <code>NULL</code>이 아닌 값의 개수를 반환한다.</li>
</ul>
</li>
<li><p><strong><code>MAX</code> / <code>MIN</code> (최대값 / 최소값)</strong>  </p>
<ul>
<li><code>NULL</code>을 제외한 값들 중에서 최대값과 최소값을 반환한다.</li>
</ul>
</li>
</ol>
<h3 id="예시로-이해하기">예시로 이해하기</h3>
<p>다음과 같은 데이터가 있다고 가정하자:</p>
<table>
<thead>
<tr>
<th>값</th>
</tr>
</thead>
<tbody><tr>
<td>10</td>
</tr>
<tr>
<td>NULL</td>
</tr>
<tr>
<td>20</td>
</tr>
<tr>
<td>30</td>
</tr>
</tbody></table>
<h4 id="sum-함수"><code>SUM</code> 함수</h4>
<pre><code class="language-sql">SELECT SUM(값) AS 합계 FROM 테이블;</code></pre>
<ul>
<li><code>10 + 20 + 30 = 60</code></li>
<li>결과: <code>60</code></li>
</ul>
<h4 id="avg-함수"><code>AVG</code> 함수</h4>
<pre><code class="language-sql">SELECT AVG(값) AS 평균 FROM 테이블;</code></pre>
<ul>
<li>평균 = <code>합계 / NULL이 아닌 값의 개수 = 60 / 3</code></li>
<li>결과: <code>20</code></li>
</ul>
<h4 id="count-함수"><code>COUNT</code> 함수</h4>
<pre><code class="language-sql">SELECT COUNT(*) AS 전체행, COUNT(값) AS 값개수 FROM 테이블;</code></pre>
<ul>
<li><code>COUNT(*)</code>: 전체 행의 개수(4개)를 반환 (NULL 포함).</li>
<li><code>COUNT(값)</code>: <code>NULL</code>이 아닌 값만 세기 때문에 3을 반환.</li>
<li>결과: <code>전체행 = 4</code>, <code>값개수 = 3</code></li>
</ul>
<h4 id="max--min-함수"><code>MAX</code> / <code>MIN</code> 함수</h4>
<pre><code class="language-sql">SELECT MAX(값) AS 최대값, MIN(값) AS 최소값 FROM 테이블;</code></pre>
<ul>
<li>최대값: <code>30</code></li>
<li>최소값: <code>10</code></li>
<li><code>NULL</code>은 무시되므로 계산에 포함되지 않음.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[계층형 데이터 모델에서의 '셀프 조인']]></title>
            <link>https://velog.io/@cosmo_numm/%EA%B3%84%EC%B8%B5%ED%98%95-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EC%97%90%EC%84%9C%EC%9D%98-%EC%85%80%ED%94%84-%EC%A1%B0%EC%9D%B8</link>
            <guid>https://velog.io/@cosmo_numm/%EA%B3%84%EC%B8%B5%ED%98%95-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EC%97%90%EC%84%9C%EC%9D%98-%EC%85%80%ED%94%84-%EC%A1%B0%EC%9D%B8</guid>
            <pubDate>Wed, 13 Nov 2024 12:22:27 GMT</pubDate>
            <description><![CDATA[<ul>
<li>계층형 데이터 모델에서 <strong>셀프 조인(Self Join)</strong>이 필요한 이유</li>
</ul>
<hr>
<h3 id="계층형-데이터-구조란">계층형 데이터 구조란?</h3>
<p>계층형 데이터 구조는 <strong>부모-자식 관계</strong>와 같이 데이터가 계층적으로 연결된 형태를 말한다. 예를 들어, 조직도나 카테고리 트리 등이 이에 해당한다. 이러한 구조에서는 데이터 간에 상위와 하위 관계가 존재하여 계층을 이루게 된다.</p>
<h3 id="셀프-조인이-필요한-이유">셀프 조인이 필요한 이유</h3>
<p>단순히 <code>SELECT</code> 문으로 데이터를 가져오는 것만으로는 테이블 내의 계층 관계를 명확하게 표현하기 어렵다. 특정 항목의 상위 또는 하위 데이터를 함께 조회하려면, <strong>동일한 테이블을 자신과 조인하는 셀프 조인</strong>이 필요하다.</p>
<p>예를 들어, 직원 정보를 담은 테이블이 다음과 같이 있다고 가정하자:</p>
<table>
<thead>
<tr>
<th>직원 ID</th>
<th>이름</th>
<th>상사 ID</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>홍길동</td>
<td>null</td>
</tr>
<tr>
<td>2</td>
<td>김철수</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>이영희</td>
<td>1</td>
</tr>
<tr>
<td>4</td>
<td>박민수</td>
<td>2</td>
</tr>
</tbody></table>
<ul>
<li><code>직원 ID</code>는 각 직원의 고유 식별자이다.</li>
<li><code>이름</code>은 직원의 이름이다.</li>
<li><code>상사 ID</code>는 해당 직원의 상사의 <code>직원 ID</code>를 나타낸다.</li>
</ul>
<p>이때, 각 직원과 그 직원의 상사 이름을 함께 조회하려면 다음과 같이 셀프 조인을 사용한다:</p>
<pre><code class="language-sql">SELECT 직원.이름 AS 직원이름, 상사.이름 AS 상사이름
FROM 직원
LEFT JOIN 직원 AS 상사 ON 직원.상사ID = 상사.직원ID;</code></pre>
<ul>
<li><code>직원</code> 테이블을 <code>상사</code>라는 별칭으로 한 번 더 사용하여 셀프 조인을 수행한다.</li>
<li><code>ON</code> 절에서 직원의 <code>상사 ID</code>와 상사의 <code>직원 ID</code>를 연결한다.</li>
</ul>
<p><strong>결과는 다음과 같다:</strong></p>
<table>
<thead>
<tr>
<th>직원이름</th>
<th>상사이름</th>
</tr>
</thead>
<tbody><tr>
<td>홍길동</td>
<td>null</td>
</tr>
<tr>
<td>김철수</td>
<td>홍길동</td>
</tr>
<tr>
<td>이영희</td>
<td>홍길동</td>
</tr>
<tr>
<td>박민수</td>
<td>김철수</td>
</tr>
</tbody></table>
<ul>
<li>홍길동은 최고 관리자이므로 상사 이름이 <code>null</code>이다.</li>
<li>김철수와 이영희의 상사는 홍길동이다.</li>
<li>박민수의 상사는 김철수이다.</li>
</ul>
<hr>
<p>이렇게 계층형 데이터 모델에서 셀프 조인은 <strong>동일한 테이블 내에서 계층 관계를 표현하고 조회하기 위해 필수적</strong>이다. 
단순한 <code>SELECT</code> 문만으로는 부모-자식 관계를 명확하게 나타낼 수 없으므로, 셀프 조인을 통해 계층 구조의 데이터를 효과적으로 다룰 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제3 정규화(3NF) - 이행적 종속성 제거 ]]></title>
            <link>https://velog.io/@cosmo_numm/%EC%A0%9C3-%EC%A0%95%EA%B7%9C%ED%99%943NF-%EC%9D%B4%ED%96%89%EC%A0%81-%EC%A2%85%EC%86%8D%EC%84%B1-%EC%A0%9C%EA%B1%B0</link>
            <guid>https://velog.io/@cosmo_numm/%EC%A0%9C3-%EC%A0%95%EA%B7%9C%ED%99%943NF-%EC%9D%B4%ED%96%89%EC%A0%81-%EC%A2%85%EC%86%8D%EC%84%B1-%EC%A0%9C%EA%B1%B0</guid>
            <pubDate>Wed, 13 Nov 2024 11:29:41 GMT</pubDate>
            <description><![CDATA[<p>제 3 정규화(3NF)는 <strong>이행적 종속(Transitive Dependency)</strong>을 제거하여 데이터를 보다 효율적으로 관리하는 단계이다.</p>
<h3 id="제-3-정규화의-목적">제 3 정규화의 목적</h3>
<p>제 3 정규화는 테이블 내에서 <strong>기본 키가 아닌 컬럼이 다른 비키(non-key) 컬럼을 결정하지 않도록</strong> 만드는 것이다. 즉, 기본 키에 대해서만 종속성을 갖도록 하여 데이터의 중복을 줄이고, 이상 현상(Anomalies)을 방지하는 것이 목적이다.</p>
<h3 id="이행적-종속transitive-dependency이란">이행적 종속(Transitive Dependency)이란?</h3>
<ul>
<li><strong>이행적 종속</strong>은 비키 컬럼이 또 다른 비키 컬럼을 결정하는 관계를 의미한다.</li>
<li>예를 들어, <code>학생 테이블</code>에서 기본 키가 <code>학생 ID</code>라고 할 때, <code>학생 ID → 학과 ID → 학과 이름</code>과 같은 형태가 이행적 종속이다. 이 경우 <code>학생 ID</code>는 <code>학과 이름</code>을 직접 결정하지 않고, 중간의 <code>학과 ID</code>를 통해서 결정하는 관계가 발생한다.</li>
</ul>
<h3 id="제-3-정규화-과정">제 3 정규화 과정</h3>
<ol>
<li>이행적 종속 관계가 있는 컬럼을 분리하여 새로운 테이블을 생성한다.</li>
<li>생성된 새로운 테이블에 기본 키를 추가하여 나머지 속성들이 오직 그 기본 키에 종속되도록 만든다.</li>
</ol>
<h3 id="예시">예시</h3>
<h4 id="제-3-정규화-전-이행적-종속-존재">제 3 정규화 전 (이행적 종속 존재)</h4>
<table>
<thead>
<tr>
<th>학생 ID</th>
<th>학생 이름</th>
<th>학과 ID</th>
<th>학과 이름</th>
</tr>
</thead>
<tbody><tr>
<td>101</td>
<td>김철수</td>
<td>D01</td>
<td>컴퓨터공학과</td>
</tr>
<tr>
<td>102</td>
<td>이영희</td>
<td>D02</td>
<td>기계공학과</td>
</tr>
<tr>
<td>103</td>
<td>박민수</td>
<td>D01</td>
<td>컴퓨터공학과</td>
</tr>
</tbody></table>
<p>위 테이블에서는 <code>학생 ID</code>가 기본 키다. <code>학과 ID</code>는 <code>학생 ID</code>에 종속되어 있지만, <code>학과 이름</code>이 <code>학과 ID</code>에 종속되는 이행적 종속이 발생하고 있다.</p>
<h4 id="제-3-정규화-후-이행적-종속-제거">제 3 정규화 후 (이행적 종속 제거)</h4>
<p><strong>학생 테이블</strong></p>
<table>
<thead>
<tr>
<th>학생 ID</th>
<th>학생 이름</th>
<th>학과 ID</th>
</tr>
</thead>
<tbody><tr>
<td>101</td>
<td>김철수</td>
<td>D01</td>
</tr>
<tr>
<td>102</td>
<td>이영희</td>
<td>D02</td>
</tr>
<tr>
<td>103</td>
<td>박민수</td>
<td>D01</td>
</tr>
</tbody></table>
<p><strong>학과 테이블</strong></p>
<table>
<thead>
<tr>
<th>학과 ID</th>
<th>학과 이름</th>
</tr>
</thead>
<tbody><tr>
<td>D01</td>
<td>컴퓨터공학과</td>
</tr>
<tr>
<td>D02</td>
<td>기계공학과</td>
</tr>
</tbody></table>
<p>이제 <code>학생 테이블</code>에서 <code>학과 이름</code> 컬럼을 분리하여 <code>학과 테이블</code>을 생성함으로써 이행적 종속을 제거했다. 이제 <code>학생 테이블</code>에서는 모든 속성이 기본 키인 <code>학생 ID</code>에 대해서만 직접적으로 종속되어 있으며, <code>학과 테이블</code>에서도 <code>학과 ID</code>가 <code>학과 이름</code>을 결정하게 되어 중복을 줄이고 데이터의 일관성을 유지할 수 있게 된다.</p>
<p>이처럼 제 3 정규화를 통해 데이터베이스가 보다 깔끔하고 효율적인 구조를 가지게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제2 정규화(2NF) - 완전 함수적 종속화 ]]></title>
            <link>https://velog.io/@cosmo_numm/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%95%EA%B7%9C%ED%99%94-2NF-%EC%99%84%EC%A0%84-%ED%95%A8%EC%88%98%EC%A0%81-%EC%A2%85%EC%86%8D%ED%99%94</link>
            <guid>https://velog.io/@cosmo_numm/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%95%EA%B7%9C%ED%99%94-2NF-%EC%99%84%EC%A0%84-%ED%95%A8%EC%88%98%EC%A0%81-%EC%A2%85%EC%86%8D%ED%99%94</guid>
            <pubDate>Wed, 13 Nov 2024 10:54:36 GMT</pubDate>
            <description><![CDATA[<p>제 2 정규화(2NF)는 <strong>부분 함수적 종속</strong>을 제거하여 <strong>완전 함수적 종속</strong>을 가지게 만드는 과정이다.</p>
<ol>
<li><p><strong>함수적 종속(Functional Dependency)</strong>란 하나의 컬럼이 다른 컬럼을 결정하는 관계를 의미한다. 예를 들어, <code>학생 ID</code>가 <code>학생 이름</code>을 결정할 수 있다면, <code>학생 이름</code>은 <code>학생 ID</code>에 함수적으로 종속되어 있다고 할 수 있다.</p>
</li>
<li><p><strong>부분 함수적 종속(Partial Dependency)</strong>이란 복합 키(여러 개의 컬럼이 합쳐져 기본 키 역할을 하는 경우)를 사용하는 테이블에서, 기본 키의 일부만으로 특정 컬럼이 종속되는 것을 의미한다. 예를 들어, <code>수강 테이블</code>에서 <code>(학생 ID, 과목 ID)</code>가 기본 키라면, <code>학생 이름</code>이 <code>학생 ID</code>에만 종속되는 경우가 발생할 수 있다. 이때 <code>학생 이름</code>은 전체 기본 키 <code>(학생 ID, 과목 ID)</code>에 대해 부분적으로만 종속된 것이다.</p>
</li>
<li><p><strong>완전 함수적 종속(Full Functional Dependency)</strong>이란 기본 키의 모든 컬럼에 대해 종속된 상태를 의미한다. 제 2 정규화를 달성하려면 기본 키의 일부가 아닌 전체에 대해 완전히 종속되어야 한다.</p>
</li>
</ol>
<p><strong>제 2 정규화 과정</strong>은 이러한 부분 함수적 종속을 제거하기 위해 <strong>부분적으로 종속된 컬럼들을 별도의 테이블로 분리</strong>하는 것이다. 예를 들어, <code>학생 ID</code>와 관련된 속성들(예: 학생 이름, 학년)을 새로운 테이블 <code>학생 테이블</code>로 분리하여, <code>수강 테이블</code>에서는 완전하게 종속된 속성들만 남겨두는 방식으로 나눌 수 있다.</p>
<p>이 과정을 통해 데이터 중복을 줄이고 테이블 구조가 보다 효율적으로 변하게 된다.</p>
<hr>
<p>아래는 제 2 정규화 전후의 예시를 테이블로 정리한 것이다. 이 예시는 <code>수강 테이블</code>을 기준으로 부분 함수적 종속을 제거하는 과정을 보여준다.</p>
<h3 id="제-2-정규화-전-부분-함수적-종속-존재">제 2 정규화 전 (부분 함수적 종속 존재)</h3>
<table>
<thead>
<tr>
<th>학생 ID</th>
<th>과목 ID</th>
<th>학생 이름</th>
<th>학년</th>
<th>과목 이름</th>
</tr>
</thead>
<tbody><tr>
<td>101</td>
<td>A01</td>
<td>김철수</td>
<td>3학년</td>
<td>데이터베이스</td>
</tr>
<tr>
<td>102</td>
<td>A02</td>
<td>이영희</td>
<td>2학년</td>
<td>운영체제</td>
</tr>
<tr>
<td>101</td>
<td>A02</td>
<td>김철수</td>
<td>3학년</td>
<td>운영체제</td>
</tr>
<tr>
<td>103</td>
<td>A03</td>
<td>박민수</td>
<td>1학년</td>
<td>네트워크</td>
</tr>
</tbody></table>
<p>위의 테이블에서는 <code>학생 ID</code>와 <code>과목 ID</code>가 복합 기본 키다. 하지만 <code>학생 이름</code>과 <code>학년</code>은 <code>학생 ID</code>에만 종속되어 부분 함수적 종속이 발생하고 있다.</p>
<h3 id="제-2-정규화-후-완전-함수적-종속">제 2 정규화 후 (완전 함수적 종속)</h3>
<p><strong>학생 테이블</strong></p>
<table>
<thead>
<tr>
<th>학생 ID</th>
<th>학생 이름</th>
<th>학년</th>
</tr>
</thead>
<tbody><tr>
<td>101</td>
<td>김철수</td>
<td>3학년</td>
</tr>
<tr>
<td>102</td>
<td>이영희</td>
<td>2학년</td>
</tr>
<tr>
<td>103</td>
<td>박민수</td>
<td>1학년</td>
</tr>
</tbody></table>
<p><strong>수강 테이블</strong></p>
<table>
<thead>
<tr>
<th>학생 ID</th>
<th>과목 ID</th>
<th>과목 이름</th>
</tr>
</thead>
<tbody><tr>
<td>101</td>
<td>A01</td>
<td>데이터베이스</td>
</tr>
<tr>
<td>102</td>
<td>A02</td>
<td>운영체제</td>
</tr>
<tr>
<td>101</td>
<td>A02</td>
<td>운영체제</td>
</tr>
<tr>
<td>103</td>
<td>A03</td>
<td>네트워크</td>
</tr>
</tbody></table>
<p>이제 <code>학생 테이블</code>과 <code>수강 테이블</code>로 분리되어, <code>학생 ID</code>와 관련된 <code>학생 이름</code>과 <code>학년</code> 속성들이 완전 함수적 종속 관계를 갖게 되었다. 이를 통해 데이터의 중복이 줄어들고, 테이블이 보다 효율적으로 관리될 수 있게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[커넥티 테스트코드(3) 다른 코드 비교 ]]></title>
            <link>https://velog.io/@cosmo_numm/%EC%BB%A4%EB%84%A5%ED%8B%B0-%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%BD%94%EB%93%9C3-%EB%8B%A4%EB%A5%B8-%EC%BD%94%EB%93%9C-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@cosmo_numm/%EC%BB%A4%EB%84%A5%ED%8B%B0-%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%BD%94%EB%93%9C3-%EB%8B%A4%EB%A5%B8-%EC%BD%94%EB%93%9C-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Tue, 05 Nov 2024 10:48:27 GMT</pubDate>
            <description><![CDATA[<p>두 테스트 코드의 차이점을 설명하면서, 각 코드가 어떻게 작동하는지와 추가된 부분의 의미를 설명해드리겠습니다.</p>
<hr>
<h3 id="첫-번째-테스트-코드">첫 번째 테스트 코드</h3>
<pre><code class="language-java">@Test
@DisplayName(&quot;Post 작성 성공&quot;)
void testCreatePostSuccess() {
    String title = &quot;Sample Title&quot;;
    String body = &quot;Sample body&quot;;
    String userName = &quot;sampleUserName&quot;;

    // Mocking
    when(userEntityRepository.findByUserName(userName)).thenReturn(Optional.of(mock(UserEntity.class)));
    when(PostEntityRepository.save(any(PostEntity.class))).thenReturn(mock(PostEntity.class));

    PostEntity mockPost = new PostEntity(title, body);
    when(PostEntityRepository.save(any())).thenReturn(mockPost);

    Assertions.assertDoesNotThrow(() -&gt; postService.createPost(title, body, userName)); 
}</code></pre>
<h4 id="설명">설명</h4>
<ol>
<li><strong><code>userEntityRepository</code> Mocking</strong>: <code>findByUserName(userName)</code> 호출 시 모의 <code>UserEntity</code> 객체를 반환하도록 설정하여, 데이터베이스에 실제 사용자가 있는 것처럼 시뮬레이션합니다.</li>
<li><strong><code>PostEntityRepository</code> Mocking</strong>:<ul>
<li><code>PostEntityRepository.save(any(PostEntity.class))</code> 호출 시 <code>mock(PostEntity.class)</code> 객체가 반환되도록 설정합니다.</li>
<li>이후 <code>PostEntity mockPost</code>를 생성하여, <code>PostEntityRepository.save(any())</code> 호출 시 <code>mockPost</code>를 반환하도록 추가로 설정합니다.</li>
</ul>
</li>
<li><strong><code>Assertions.assertDoesNotThrow(...)</code></strong>: <code>postService.createPost(...)</code> 호출 시 예외가 발생하지 않는지 확인합니다. <strong>여기서 예외가 발생하면 안 되는 이유</strong>는, 성공적인 Post 생성 로직이 실행되었음을 확인하는 테스트이기 때문입니다. 예외가 발생하면 Post 생성이 실패한 것으로 간주됩니다.</li>
</ol>
<h4 id="특징">특징</h4>
<ul>
<li>이 테스트는 <strong>기본적인 Mocking</strong>만 수행하고 있습니다.</li>
<li><code>PostEntity</code> 인스턴스를 두 번 Mocking하는 불필요한 중복이 있을 수 있습니다. </li>
</ul>
<hr>
<h3 id="두-번째-테스트-코드">두 번째 테스트 코드</h3>
<pre><code class="language-java">@Test
@DisplayName(&quot;Post 작성 성공&quot;)
void testCreatePostSuccess() {
    TestInfoFixture.TestInfo fixture = TestInfoFixture.get();

    when(userEntityRepository.findByUserName(fixture.getUserName()))
        .thenReturn(Optional.of(UserEntityFixture.get(fixture.getUserName(), fixture.getPassword())));
    when(postEntityRepository.save(any())).thenReturn(mock(PostEntity.class));

    Assertions.assertDoesNotThrow(() -&gt; 
        postService.createPost(fixture.getUserName(), fixture.getTitle(), fixture.getBody())
    );
}</code></pre>
<h4 id="설명-1">설명</h4>
<ol>
<li><strong><code>TestInfoFixture</code>를 사용한 Mocking</strong>: <code>TestInfoFixture.get()</code> 메서드를 사용하여 <code>fixture</code> 객체를 받아옵니다. 이 객체는 <strong>테스트용 데이터를 포함</strong>한 객체로, <code>userName</code>, <code>title</code>, <code>body</code> 등의 속성을 가진 <code>TestInfoFixture.TestInfo</code> 인스턴스입니다.</li>
<li><strong>Fixture를 사용한 데이터 설정</strong>:<ul>
<li><code>UserEntityFixture.get(...)</code>을 통해 실제와 유사한 <code>UserEntity</code> 객체를 생성하고 반환합니다. 이는 데이터가 일관된 형태를 유지하도록 도와주어 테스트의 가독성을 높입니다.</li>
<li><code>userEntityRepository.findByUserName(fixture.getUserName())</code>이 호출되면 <code>UserEntityFixture.get(...)</code>을 통해 생성된 모의 <code>UserEntity</code>가 반환되도록 설정합니다.</li>
</ul>
</li>
<li><strong><code>postEntityRepository.save(any())</code> Mocking</strong>: <code>postEntityRepository.save(any())</code>가 호출될 때 모의 <code>PostEntity</code> 객체를 반환하도록 설정합니다.</li>
</ol>
<h4 id="특징-1">특징</h4>
<ul>
<li><strong>Fixture를 통해 데이터의 일관성을 유지</strong>합니다. Fixture는 여러 테스트에서 동일한 데이터를 사용하여, 테스트 코드의 반복을 줄이고 코드 가독성을 높입니다.</li>
<li><strong>더 깔끔한 Mocking</strong>: PostEntity의 Mocking이 단일 호출로 이루어지며, 첫 번째 테스트에 비해 불필요한 Mocking이 줄어듭니다.</li>
</ul>
<hr>
<h3 id="비교-및-차이점-요약">비교 및 차이점 요약</h3>
<table>
<thead>
<tr>
<th>특성</th>
<th>첫 번째 테스트</th>
<th>두 번째 테스트</th>
</tr>
</thead>
<tbody><tr>
<td><strong>데이터 설정 방식</strong></td>
<td>하드코딩된 문자열 사용</td>
<td><code>TestInfoFixture</code>를 통한 테스트 데이터 설정</td>
</tr>
<tr>
<td><strong>Mocking 중복 여부</strong></td>
<td><code>PostEntityRepository.save</code> 중복 Mocking</td>
<td><code>postEntityRepository.save</code> 단일 Mocking</td>
</tr>
<tr>
<td><strong>Fixture 사용 여부</strong></td>
<td>사용하지 않음</td>
<td><code>UserEntityFixture</code> 및 <code>TestInfoFixture</code> 사용</td>
</tr>
<tr>
<td><strong>테스트 가독성</strong></td>
<td>하드코딩으로 코드가 길어질 수 있음</td>
<td>Fixture로 더 읽기 쉽고 관리가 용이함</td>
</tr>
</tbody></table>
<p><strong>결론적으로, 두 번째 코드가 Fixture를 통해 데이터 일관성을 제공하고, 중복된 Mocking을 제거하여 가독성과 유지보수성을 높인 테스트 코드</strong>입니다. Fixture를 적극적으로 활용하면 코드의 구조가 더 명확해지고 테스트 유지 관리가 용이해집니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Connecti] TDD 적용 - 로그인 테스트 ]]></title>
            <link>https://velog.io/@cosmo_numm/Connecti-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@cosmo_numm/Connecti-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C</guid>
            <pubDate>Fri, 01 Nov 2024 06:34:11 GMT</pubDate>
            <description><![CDATA[<h3 id="tdd-진행-중-작성한-로그인-성공-테스트-과정-기록">TDD 진행 중 작성한 로그인 성공 테스트 과정 기록</h3>
<h4 id=""></h4>
<p>로그인 성공을 테스트하기 위해 다음과 같이 코드를 작성했지만, <code>encoder.matches(...)</code> 부분에서 에러가 발생함</p>
<pre><code class="language-java">@Test
@DisplayName(&quot;로그인 성공: 올바른 사용자명과 비밀번호&quot;)
void testUserLoginSuccess() {
    // 테스트에 필요한 사용자 정보를 설정
    String userName = &quot;testuser&quot;;
    String password = &quot;password&quot;;

    // Fixture로 테스트용 가짜 UserEntity 생성
    UserEntity fixture = UserEntityFixture.get(1L, userName, password);

    // Mocking 설정
    when(userEntityRepository.findByUserName(userName)).thenReturn(Optional.of(fixture));

    // 실제 메서드 실행 및 성공 여부 검증
    Assertions.assertDoesNotThrow(() -&gt; userService.login(userName, password));
}</code></pre>
<p>이 코드에서는 <code>userEntityRepository.findByUserName(userName)</code>의 결과를 Mocking하여 <code>fixture</code>를 반환하도록 했으나, 테스트가 여전히 실패함</p>
<hr>
<blockquote>
<p><strong>-&gt; 이슈 해결 : <code>encoder.matches(...)</code> 부분을 추가로 Mocking 하는 코드를 추가</strong> (<strong><code>encoder.matches(...)</code> 부분에서 실제 비밀번호 비교가 이루어지지 않아 에러가 발생</strong>한 것으로 파악)</p>
</blockquote>
<p><code>encoder.matches(...)</code>는 비밀번호를 비교하는 메서드로, 로그인 시 사용자가 입력한 비밀번호와 DB에 저장된 인코딩된 비밀번호를 비교하지만,테스트 환경에서는 입력 비밀번호와 암호화된 비밀번호의 일치 여부를 파악할 필요가 없음. 
그러므로, 비밀번호가 일치한다고 가정하는 상황을 만들어주어야 테스트가 원활하게 진행되며,</p>
<p>이를 위해 <code>encoder.matches(...)</code>를 다음과 같이 기존 코드에 추가로 Mocking하여 <strong>항상 <code>true</code>를 반환</strong>하도록 설정. (mocking 의도 : 로그인 성공을 위한 테스트의 조건을 간단하게 만들기 위함 ~ Mocking으로 특정 결과를 반환하도록 설정한다.)</p>
<p>(추가한 코드)</p>
<pre><code class="language-java">when(encoder.matches(password, fixture.getPassword())).thenReturn(true);</code></pre>
<p>(정리)</p>
<ol>
<li><p>이 Mocking 설정이 없을 경우, <code>encoder.matches(...)</code>는 실제로 비밀번호를 비교하는데, 테스트에서는 이 과정이 불필요하고, 실제 암호화된 비밀번호가 없으므로 비밀번호 비교가 항상 실패하여 테스트가 실패하게 되는 것이다.</p>
</li>
<li><p>Mocking 추가 후: <code>encoder.matches(...)</code>가 <code>true</code>를 반환하도록 설정하여, <code>userService.login(...)</code> 메서드는 비밀번호가 일치한다고 가정하고 테스트가 통과됨</p>
</li>
</ol>
<hr>
<h4 id="수정-후-정상-로그인-테스트를-통과한-코드">수정 후 정상 로그인 테스트를 통과한 코드</h4>
<pre><code class="language-java">@Test
@DisplayName(&quot;로그인 성공: 올바른 사용자명과 비밀번호&quot;)
void testUserLoginSuccess() {

    // 테스트에 필요한 사용자 정보를 설정
    String userName = &quot;testuser&quot;;
    String password = &quot;password&quot;;

    // Fixture로 테스트용 가짜 UserEntity 생성
    UserEntity fixture = UserEntityFixture.get(1L, userName, password);

    // Mocking 설정
    when(userEntityRepository.findByUserName(userName)).thenReturn(Optional.of(fixture));
    when(encoder.matches(password, fixture.getPassword())).thenReturn(true); // 추가된 Mocking 설정

    // 실제 메서드 실행 및 성공 여부 검증
    Assertions.assertDoesNotThrow(() -&gt; userService.login(userName, password));
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>