<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>i-c-a-n-d-o.log</title>
        <link>https://velog.io/</link>
        <description>나는 백엔드 개발자다!</description>
        <lastBuildDate>Fri, 07 Feb 2025 01:46:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. i-c-a-n-d-o.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/i-can-do" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[TypeORM에서 ||를 사용했지만 OR 조건이 제대로 작동하지 않았던 이유 ]]></title>
            <link>https://velog.io/@i-can-do/TypeORM%EC%97%90%EC%84%9C-%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%96%88%EC%A7%80%EB%A7%8C-OR-%EC%A1%B0%EA%B1%B4%EC%9D%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%9E%91%EB%8F%99%ED%95%98%EC%A7%80-%EC%95%8A%EC%95%98%EB%8D%98-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@i-can-do/TypeORM%EC%97%90%EC%84%9C-%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%96%88%EC%A7%80%EB%A7%8C-OR-%EC%A1%B0%EA%B1%B4%EC%9D%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%9E%91%EB%8F%99%ED%95%98%EC%A7%80-%EC%95%8A%EC%95%98%EB%8D%98-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Fri, 07 Feb 2025 01:46:45 GMT</pubDate>
            <description><![CDATA[<p>개발을 하다 보면 내가 알고 있다고 생각했던 개념을 코드에 적용하지 못해서 엉뚱하게 작동할 때가 있다. 이번에도 또 그런 경험을 했다!!!</p>
<h2 id="하고-싶었던-작업">하고 싶었던 작업</h2>
<p>특정 eventType 값을 가진 데이터를 조회하고 싶었다. <strong>원하는 조건은 EventType.A 또는 EventType.B를 만족하는 데이터를 가져오는 것</strong>이었다. 그래서 아래와 같이 코드를 작성했다.</p>
<pre><code class="language-typescript">const datas =
   await this.Arepository.find({
     where: {
       eventType: EventType.A || EventType.B,
     },
   });</code></pre>
<p>이렇게 하면 eventType이 A이거나 B인 데이터를 가져올 것이라 생각했다. 하지만... 수행된 쿼리를 보니 결과가 이상했고?
어라? B 조건이 사라졌다? 🤔</p>
<blockquote>
<p>WHERE ((<code>A</code>.<code>event_type</code> = A) AND ( <code>A</code>.<code>deletedAt</code> IS NULL ) </p>
</blockquote>
<h2 id="원인을-찾아보자">원인을 찾아보자</h2>
<p>사수가 &quot;왜 B 조건이 없어졌을까요?&quot;라고 질문을 던졌다.</p>
<p>어..? 그러게 왜지? 안된다는 건 알았지만 &#39;왜&#39; 안되는 지 거기까진 생각을 해보지 않았다. 궁금해서 바로 검색을 해봤다. </p>
<h3 id="핵심-원인--연산자">핵심 원인: || 연산자</h3>
<p>내가 알고 있는 지식이였지만, 응용이 부족해서 몰랐던 부분이였다.
?? 는 널병합 연산자 ||는 논리 연산자로, <strong>앞의 조건이 true면 뒤의 조건을 보지도 않고 바로 종료</strong>된다.</p>
<pre><code class="language-typescript">const condition = EventType.A || EventType.B;</code></pre>
<p>이 코드는 EventType.A가 존재하는 값이면 그 자체가 true로 평가되기 때문에 EventType.B는 아예 무시된다. 
즉, 실제로 <strong>where: { eventType: true }</strong>처럼 동작한 것이다. 😵‍💫</p>
<h2 id="해결-방법">해결 방법</h2>
<h3 id="💡-방법1-배열을-활용한-where-조건">💡 방법1: 배열을 활용한 where 조건</h3>
<p>TypeORM에서는 where 옵션을 배열로 작성하면 OR 조건이 적용된다.</p>
<pre><code class="language-typescript">const datas =
  await this.Arepository.find({
    where: [
      {
        eventType: EventType.A,
      },
      {
        eventType: EventType.B,
      },
    ],
  });</code></pre>
<h3 id="💡-방법2-in-연산자-사용">💡 방법2: In 연산자 사용</h3>
<p>방법1이 번거로우면 In 연산자를 사용해서 원하는 결과를 얻을 수도 있다.</p>
<pre><code class="language-typescript">const datas =
   await this.Arepository.find({
     where: {
       eventType: In([EventType.A, EventType.B]),
     },
   });</code></pre>
<p>개인적으로는 방법2가 더 직관적이고 가독성도 좋다고 생각되서 2번으로 수정했다! </p>
<h2 id="remind">Remind</h2>
<ul>
<li>||는 논리 연산자로, 앞의 값이 true면 뒤를 무시한다.</li>
<li>TypeORM에서 OR 조건을 적용하려면 배열을 사용하거나 In 연산자를 활용해야 한다.</li>
</ul>
<p>두번은 틀리지 말자~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[단일 책임 원칙을 지키지 않았더니 단일 책임 원칙을 이해하게 됨]]></title>
            <link>https://velog.io/@i-can-do/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99%EC%9D%84-%EC%A7%80%ED%82%A4%EC%A7%80-%EC%95%8A%EC%95%98%EB%8D%94%EB%8B%88-%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99%EC%9D%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B2%8C-%EB%90%A8</link>
            <guid>https://velog.io/@i-can-do/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99%EC%9D%84-%EC%A7%80%ED%82%A4%EC%A7%80-%EC%95%8A%EC%95%98%EB%8D%94%EB%8B%88-%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99%EC%9D%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B2%8C-%EB%90%A8</guid>
            <pubDate>Tue, 21 Jan 2025 15:55:04 GMT</pubDate>
            <description><![CDATA[<p>페이지네이션을 도와주는 PaginationBuilder 라는 클래스가 따로 정의되어있었다.
해당 클래스는 아래와 같은 스타일이였다.</p>
<pre><code class="language-typescript">export class PaginationBuilder&lt;T&gt; {
  private list: T[] = [];
  private page: number = 0;
  private take: number = 0;
  private totalCount: number = 0;

  setList(list: T[]) {
    this.list = list;
    return this;
  }

  setPage(page: number) {
    this.page = page;
    return this;
  }

  ...

  build() {
    return new PaginationResponse&lt;T&gt;({
      list: this.list,
      page: this.page,
      take: this.take,
      totalCount: this.totalCount,
    });
  }
}</code></pre>
<p>PaginationBuilder 클래스는 페이지네이션 데이터(list)를 생성하는 데 초점을 두고 있는 단순한 구조의 클래스다. list, page, take, totalCount만 포함하고 있었고, 이름 그대로 페이지네이션 기능만 담당하는 역할을 하고 있었다.</p>
<p>하지만 이번에 내가 맡은 스프린트를 진행하면서 기존과 다른 스타일의 Response DTO가 필요해졌다.</p>
<p><img src="https://velog.velcdn.com/images/i-can-do/post/3b90bafa-b401-40f6-a74c-fb1316605094/image.png" alt=""></p>
<p>보면, 위 Response는 페이지네이션 데이터(list)뿐만 아니라 전체 인원 수, 메일 발송 대기 수, 메일 발송 성공 수, 메일 발송 실패 수와 같은 추가 데이터를 요구하고 있기에, 데이터들을 data라는 객체안에 담아서 반환할 수 있도록 기존의 PaginationBuilder를 수정해서 data라는 새로운 객체 타입을 추가해서 해결을 했었다. </p>
<pre><code class="language-typescript">export class PaginationBuilder&lt;T, D = undefined&gt; {
  private list: T[] = [];
  private data: D;  // 이렇게 추가함
  private page: number = 0;
  private take: number = 0;
  private totalCount: number = 0;

  setList(list: T[]) {
    if (!isArray(list)) {
      return this;
    }

    this.list = list;
    return this;
  }

  // 이렇게 추가함
  setData(data: D) {  
    this.data = data;
    return this;
  }

 ...

  build() {
    return new PaginationResponse&lt;T, D&gt;({
      list: this.list,
      page: this.page,
      take: this.take,
      totalCount: this.totalCount,
      data: this.data,  // 이렇게 추가함
    });
  }
}</code></pre>
<p>위 코드는 단일 책임 원칙(SRP)을 위반했기 때문에 <strong>잘못된 코드</strong>다. </p>
<p>기존의 PaginationBuilder는 페이지네이션 관련 데이터를 생성하는 데 포커스를 두고 있었는데, 내가 data를 추가함으로서 이제는 페이지네이션과 관계없는 data를 처리하는 역할까지 떠맡게 된 셈이였다.</p>
<p>또 만약 새로운 요구사항이 생기면, 그때도 나는 PaginationBuilder에 추가하려고 할텐데, 그렇게 되면 PaginationBuilder 클래스가 점점 커지고 복잡해지게 된다. 
이는 흔히들 알고 있는 안티 패턴, 코드의 재사용성과 확장성을 떨어뜨리는 안좋은 방식이다.</p>
<p>이를 해결하기 위해, 즉 단일 책임 원칙을 준수하기 위해서는 아래와 같은 방식으로 해결이 가능하다.</p>
<ol>
<li>PaginationBuilder를 상속받아서 새로운 뭐 DataPaginationBuilder를 구현한다던가,</li>
<li>아니면 스프레드 연산자를 사용해서 data를 추가하는 방식도 가능하다.
✅ 내가 채택한 방식</li>
</ol>
<pre><code class="language-typescript">const paginationBuilder = paginationBuilder.build();
const result = {
                  ...paginationBuilder,
                  data: additionalData,
                  };</code></pre>
<p>2번처럼 간단하게 해결이 가능했는데, 왜 그걸 생각 못했을까? 🫠</p>
<p>역시 역시 책이나 이론으로 배우는 것보다 직접 코드를 작성하면서 실수를 통해 배우는 게 더 오래 기억에 남는 것 같다. 그렇게 단일 책임 원칙이 뭘까 블로그에도 정리했었는데, 코드 치면서 뚜까 맞았더니 바로 이해해버렸다!!</p>
<p>앞으로는 클래스를 설계할 때 과연 이 클래스는 단 하나의 책임만 가지고 있는가를 스스로에게 되물으면서 코드를 작성할 수 있게 됐다!</p>
<p>아주 재밌는 하루였다 :) </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[회고) 입사 후 첫 스프린트를 마쳤는데 난 아직 기본이 안됐다ㅠㅠ]]></title>
            <link>https://velog.io/@i-can-do/%ED%9A%8C%EA%B3%A0-%EC%9E%85%EC%82%AC-%ED%9B%84-%EC%B2%AB-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8%EB%A5%BC-%EB%A7%88%EC%B3%A4%EB%8A%94%EB%8D%B0-%EB%82%9C-%EC%95%84%EC%A7%81-%EA%B8%B0%EB%B3%B8%EC%9D%B4-%EC%95%88%EB%90%90%EB%8B%A4%E3%85%A0%E3%85%A0</link>
            <guid>https://velog.io/@i-can-do/%ED%9A%8C%EA%B3%A0-%EC%9E%85%EC%82%AC-%ED%9B%84-%EC%B2%AB-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8%EB%A5%BC-%EB%A7%88%EC%B3%A4%EB%8A%94%EB%8D%B0-%EB%82%9C-%EC%95%84%EC%A7%81-%EA%B8%B0%EB%B3%B8%EC%9D%B4-%EC%95%88%EB%90%90%EB%8B%A4%E3%85%A0%E3%85%A0</guid>
            <pubDate>Tue, 07 Jan 2025 14:28:55 GMT</pubDate>
            <description><![CDATA[<p>새로 합류한 회사에서 첫 번째 스프린트를 끝냈다. 
이번 회고는 첫 스프린트 동안의 느낀 점, 반성, 그리고 앞으로의 다짐을 정리하는 기록이다.  </p>
<h3 id="스프린트-시작-설계가-끝난-상태에서의-시작">스프린트 시작: 설계가 끝난 상태에서의 시작</h3>
<p>첫 스프린트는 팀 리더가 이미 테이블 설계와 데이터 모델링을 마무리한 상태에서 시작했다. 백엔드 개발에 있어서 설계가 제일 빡세다고 생각하고, 그래서 BE 개발의 꽃이라고 생각하는데, 이걸 내가 안 해도 된다니 작업이 수월하겠다고 생각했다. 하지만... 참조해야 할 테이블이 왜 이렇게 많냐?  </p>
<p>기본적으로 4~5개의 테이블은 건드려야 하나의 API가 만들어지는 구조였다. 조회 성능 최적화를 위해 데이터가 분산 저장되어 있었는데, 이 방식이 전 직장에서 쓰던 설계와는 너무 달라서 구조를 이해하는 데 꽤 오래 걸렸다. </p>
<p>특히 역정규화를 이렇게 자유롭게(?) 활용하는 설계 방식을 처음 겪어봤다. 작업이 끝난 지금은 그 구조가 효율적이라고 느껴지지만, 당시에는 낯선 설계 방식과 컨벤션을 파악하느라 고생 좀 했다.  </p>
<p>그리고 정책 문서가 따로 없어서 하나하나 사수에게 물어보며 진행해야 했던 점도 불편했다. 원래 모르거나 이해가 안가는 건 바로 바로 물어보는 성격이라 질문하는 건 어렵지 않았지만, 물어보는 데 걸리는 시간 때문에 작업 속도가 더뎌질 수밖에 없었다. 게다가 많이 물어보다 보니 이미 들었던 질문을 또 하고, 반복되는 질문에 사수가 저번에 설명 드렸는데~ 하면서 답해줄 때는 약간 빡친 게 아닐까 싶어 쫄리기도 했다. </p>
<p>근데 어쩌겠어, 지금 물어봐야 나중에 덜 혼난다. 그렇게 눈치보면서 계속 물어보며  작업을 진행했다. 죄송합니다 나중에 잘할께요!!</p>
<h3 id="아직도-부족하다고-느낀-api-설계">아직도 부족하다고 느낀 API 설계</h3>
<p>API 설계는 자신 있었다! 전 직장에서 몇 번의 스프린트를 거치며 해왔던 작업이라 익숙하다고 생각했다. 하지만, 이번에 목 데이터를 설계하면서도 실수를 반복했다.  </p>
<p>클라이언트 작업이 빨리 진행될 수 있도록 목 데이터를 기반으로 API를 설계했는데, 이후 작업 도중 클라이언트와 협의 없이 Response DTO를 수정하거나, 기존에 NOT NULL로 내려가던 데이터를 갑자기 Nullable로 바꾼 적이 있었다. 심지어 속성 이름까지 수정했는데, 이런 변경들이 프론트에서 문제를 일으켰다. 
전 직장에서도 똑같은 실수를 했었는데, 그걸 다시 반복했다는 게 너무 한심했다..</p>
<p>결국 리더가 프론트와 소통하는 방법에 대해 따로 미팅을 잡았고, 어떤 경우에 서로에게 의견을 물어야 하는 지 설명해줬다. 
이 미팅이 나 때문에 열렸구나 싶어 다른 팀원들에게 너무 미안했고 한편으로는 또 감사했다 ㅠㅠ 나 때문에 얼마나 힘드셨을까... 그래도 설명해주신다고 자리도 마련해주고 흑</p>
<p>가시방석에서 진행됐던 미팅이였지만, 실수는 누구나 할 수 있어.. 줄여 나가면 돼!! 나 자신을 다독이며 잘 이겨냈지만, 여전히 마음 속 죄송한 마음이 든다 ㅠㅠ</p>
<h3 id="실수에서-얻은-교훈">실수에서 얻은 교훈</h3>
<ol>
<li><p><strong>소통의 중요성</strong><br>API 설계에서 클라이언트와의 협의는 필수다. 설계 단계에서 피드백을 주고받아야만 예기치 못한 문제를 줄일 수 있다.  </p>
</li>
<li><p><strong>변경 사항은 사전 공유</strong><br>데이터 타입이나 속성 이름 변경은 클라이언트 입장에서 큰 영향을 미친다. 사소한 수정도 공유하고 협의하는 습관을 들이자.  </p>
</li>
</ol>
<h3 id="다음-스프린트를-위한-다짐">다음 스프린트를 위한 다짐</h3>
<ol>
<li><p><strong>목 데이터 설계와 공유</strong><br>개발 시작 전에 목 데이터를 기반으로 한 API 설계를 명확히 정리하고, 클라이언트와 충분히 공유하겠다.  </p>
</li>
<li><p><strong>클라이언트 친화적인 API 설계</strong><br>클라이언트가 원하는 데이터를 정확히 제공할 수 있도록 더 유연한 설계를 시도하겠다. 필요하다면 도움을 요청하는 것도 주저하지 말자.  </p>
</li>
</ol>
<h3 id="결론-실수는-성장의-발판이다">결론: 실수는 성장의 발판이다</h3>
<p>이번 스프린트는 실수와 반성으로 가득했지만, 이 경험을 통해 또 많은 걸 배웠다고 생각한다. 클라이언트가 같이 일하고 싶은 백엔드 개발자가 되고 싶다.더 나은 소통과 설계를 보여주고 싶은데, 이게 어떻게 한번에 되겠어...
UI에서 보여지는 데이터가 정적이냐 동적이냐에 따라 판단해봐라는 팁을 기억하자.
또 설계하는 방법에서는, &#39;감&#39;이라는 게 있다고 한다. 
n번 반복하다보면 나에게도 감이 생기지 않을까!!? 포기만 하지말자!!! </p>
<p>다음 회고에서는 실수보다 더 많은 성공 경험을 적을 수 있었으면 좋겠다ㅠㅠ</p>
<p>사실 이번 스프린트에서 잘한 점도 꽤 많다.
저번에 배웠던 Map, 빌더 패턴, 우리만의 어메이징한 인증 가드 등 해당 코드들을 참고해서 나에게 맞게끔 적용도 했다. 
비록 지금은 고작 응용 따위였지만, 응용을 할 줄 알면 나중에는 직접 만들 수도 있을 거야...!! 고생했다 나 자신!</p>
<p>그래도 QA에서 예상보다 적은 버그가 발견됐으니, 그건 또 꼼꼼하게 작업했다는 증거라고 생각한다. 꼼꼼하니까 다음 스프린트는 클라이언트와 더 잘 소통할 수 있어!! </p>
<p>다음 스프린트는, 아쉬웠던 점 말고 잘한 점을 적을 수 있도록 최선을 다해봐야겠다.
다음 스프린트도 파이팅!! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[5개월의 공백을 지나, 벌써 닝닝 3주차가 되었다.]]></title>
            <link>https://velog.io/@i-can-do/5%EA%B0%9C%EC%9B%94%EC%9D%98-%EA%B3%B5%EB%B0%B1%EC%9D%84-%EC%A7%80%EB%82%98-%EB%B2%8C%EC%8D%A8-%EB%8B%9D%EB%8B%9D-3%EC%A3%BC%EC%B0%A8%EA%B0%80-%EB%90%98%EC%97%88%EB%8B%A4</link>
            <guid>https://velog.io/@i-can-do/5%EA%B0%9C%EC%9B%94%EC%9D%98-%EA%B3%B5%EB%B0%B1%EC%9D%84-%EC%A7%80%EB%82%98-%EB%B2%8C%EC%8D%A8-%EB%8B%9D%EB%8B%9D-3%EC%A3%BC%EC%B0%A8%EA%B0%80-%EB%90%98%EC%97%88%EB%8B%A4</guid>
            <pubDate>Sat, 30 Nov 2024 03:13:57 GMT</pubDate>
            <description><![CDATA[<h3 id="5개월의-공백기를-지나-드디어-취업-성공-🎉">5개월의 공백기를 지나, 드디어 취업 성공! 🎉</h3>
<p>드디어!!! 길었던 공백기를 지나 취업에 성공했다!!
이번 취업은 내게 정말 많은 것을 깨닫게 해줬다. 
무엇보다 운이 얼마나 중요한지 다시 한 번 느꼈다.분명 나보다 뛰어난 지원자들이 많았을텐데.. 결국 <strong>회사와의 &quot;핏(Fit)&quot;</strong> 역시 매우 중요한 요소라는 걸 깨달았다.</p>
<p>입사 후, 왜 나를 뽑았는가 물어봤는데 아래 3가지를 좋게 봐주셨다고 한다.</p>
<ol>
<li>성장에 대한 욕심</li>
<li>문제를 대하는 사고 방식</li>
<li>개발에 대한 재미</li>
</ol>
<p>하긴, 
이 세가지를 모두 가진 사람 바로 나야~!!! </p>
<p>다음 이직때는 위 세가지에 + 개발능력까지 보태고 말겠다.
지원자의 모든 깃허브에 다 들어가보는 우리 개발팀 리더 카리나님.</p>
<p>사실 전 회사에서 일하면서 부터는 개인 레포에 뭘 작성한 게 없었는데 창피했다.
이번에는 그렇지 않기를.
회사에서 배우는? 것들을 개인 레포에 다시 복습이라도 좋으니 기록해둬야겠다고 느꼈다.</p>
<h3 id="채용-과정의-특징">채용 과정의 특징</h3>
<p>이번 회사의 채용 프로세스는 조금 특이했다.</p>
<ul>
<li>1차 면접: 컬처핏</li>
<li>2차 면접: 기술 인터뷰</li>
</ul>
<p>컬처핏 면접은 예상보다 길었고, 기술 면접은 생각보다 어렵지 않았다. 
기술 면접을 끝내고 나니, 이 회사는 &quot;기본기만 갖추고 있으면 우리가 성장할 기회를 많이 줄 수 있다&quot;는 메시지를 전하고자 한다는 느낌이 들었다.
&quot;많이&quot; 줄 수 있다...!!! 😅
걱정도 됐지만, 동시에 &quot;오, 재밌겠는데?&quot;라는 생각이 들며 나도 모르게 입꼬리가 씰룩댔던 것 같다.</p>
<p>사실 면접을 보러 가기 전까지는 회사에 대해 확신이 없었다.
회사에 대한 정보가 많지도 않았고, 면접 중에 들었던 연봉이나 복지 수준도 기대에 미치지 못했다.
(이게 참 웃긴 게, 서류 탈락할 때는 내가 전 직장에서 아무것도 안 했던 것처럼 느껴지면서 자존감이 바닥을 쳤는데, 막상 나를 좋게 봐주는 회사를 만나니 또 욕심이 생기더라. 🤔 아마 이건 누구나 비슷한 마음이지 않을까?)</p>
<p>하지만 회사에서 나를 좋게 봐줬고, 감사하게도 좋은 기회를 잡을 수 있었다.</p>
<h3 id="이번-취업을-통해-배운-것들">이번 취업을 통해 배운 것들</h3>
<ol>
<li><p>이력서는 주기적으로 수정하자.
나중에 쓰려고 하면 기억이 나질 않는다. 항상 업데이트하는 습관을 들이자.</p>
</li>
<li><p>연봉은 천천히 늘려가자.
지금은 성장이 우선이다. 경력을 쌓고 많이 뒹굴다 보면 자연스럽게 내 가치(===돈)를 키울 수 있겠지.</p>
</li>
<li><p>재미를 느낄 수 있는 서비스에서 일하자.
이전 회사에서는 그림 관련 앱을 다뤘지만, 그림에 큰 관심이 없던 나는 회사에 깊은 애정을 느끼지 못했다.
하지만 이번 회사에서는 서비스에 공감하면서 다양한 아이디어가 떠오르고, 고민하는 과정 자체가 즐겁다.
그동안 &quot;내가 기획에는 재능이 없나?&quot;라고 생각했는데, 사실은 비전에 공감하지 못했기에 그저 흉내만 냈던 거였다는 걸 깨달았다.</p>
</li>
</ol>
<h3 id="새로운-시작">새로운 시작</h3>
<p>이제 입사한 지 겨우 3주가 되었지만, 아직까지는 만족스럽다. 
앞으로도 이 만족감이 오래 지속되면 좋겠다!!</p>
<p>닝닝, 파이팅! 🙌</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[기술 면접에서 놓친 N+1 문제]]></title>
            <link>https://velog.io/@i-can-do/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91%EC%97%90%EC%84%9C-%EB%86%93%EC%B9%9C-N1-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@i-can-do/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91%EC%97%90%EC%84%9C-%EB%86%93%EC%B9%9C-N1-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Wed, 30 Oct 2024 16:34:51 GMT</pubDate>
            <description><![CDATA[<p>기술 면접에서 N+1 문제에 대한 질문을 받았다. </p>
<p>개념과 발생 원인뿐만 아니라 TypeORM에서의 해결 방법까지 찾아봤었고 기술 면접 노트에도 기록해두었던 문제였다. 하지만 <strong>공부를 위한 기록이 아니라 기록을 위한 기록에 그쳤다</strong>는 걸 깨달았다.</p>
<p>면접 중 정답을 듣고 나서야 &quot;아!&quot;하고 머릿속의 물음표가 느낌표로 바뀌었다 ㅠㅠ
분명히 풀 수 있었고, 풀었어야 했던 문제였다. 이전 직장에서 쿼리를 작성할 때도 그렇게 했었지만, 당시엔 왜 그렇게 작성해야 하는지 깊이 생각하지 않고 넘어갔던 것이 이번 면접에서 드러난 셈이였다.😭</p>
<p>충분히 알고 있다고 생각했지만, 정작 풀지 못했던 문제.
<strong>그렇다면 내가 정말 이 문제를 알고 있었던 걸까?</strong> 라는 의문이 들었다. 
이런 일이 반복되지 않도록, 다음에 같은 상황이 또 온다면 이번에는 반드시 풀어내겠다는 다짐으로 이번 경험을 기록해두려 한다.</p>
<h1 id="eager-loading과-lazy-loading">&quot;Eager Loading&quot;과 &quot;Lazy Loading&quot;</h1>
<h2 id="eager-loading-즉시-로딩">Eager Loading (즉시 로딩)</h2>
<p>처음부터 모든 연관 데이터를 즉시 로딩하는 방법으로 접근할 때 1번의 쿼리로 참조 데이터를 모두 불러온다.</p>
<h4 id="장점">장점</h4>
<ul>
<li>필요한 데이터를 한번에 모두 가져오기 때문에 추가 쿼리가 필요없다.</li>
<li>필요한 데이터를 모두 불러왔으니, 빠른 응답이 가능하다.</li>
</ul>
<h4 id="단점">단점</h4>
<ul>
<li>연관된 모든 데이터를 가져오기 때문에 초기 로딩 시간이 길어진다.</li>
<li>클라에서 불필요한 데이터를 가져오는 _overfetching_이 발생할 수 있다.</li>
<li>엔티티가 많을 경우 Join 수의 증가로 성능 저하가 발생할 수 있다.</br>

</li>
</ul>
<h2 id="lazy-loading-지연-로딩">Lazy Loading (지연 로딩)</h2>
<p>필요한 순간에 데이터를 가져오는 방식으로 참조 데이터가 실제로 필요할 때 쿼리를 실행한다.</p>
<h4 id="장점-1">장점</h4>
<ul>
<li>연관 데이터를 모두 가져오지 않기 때문에 초기 로딩 시간을 줄일 수 있고 이는 성능 최적화와 연결된다.</li>
<li>필요한 데이터만 로드하기 때문에 불필요한 자원 낭비를 줄일 수 있다.</li>
</ul>
<h4 id="단점-1">단점</h4>
<ul>
<li>필요한 데이터마다 쿼리가 발생하므로 Eager Loading에 비해 수행되는 쿼리의 수가 많다.</li>
<li>많은 참조 데이터가 연관되어 있을 경우 추가 쿼리가 계속 발생해서 _N+1문제_가 발생할 수 있다.</li>
</ul>
<hr>
<h2 id="n--1-문제란">N + 1 문제란?</h2>
<p>1개의 쿼리로 N개의 데이터를 가져온 후 각각의 연관 데이터를 추가로 N번의 쿼리가 실행되는 문제를 말한다. 데이터 로딩 속도가 엄청 오래 걸릴 수도 있고, 이는 OOM을 발생시켜 예상치못한 버그를 발생시킬 수 있기 때문에 방지하는 것이 중요하다.</p>
<h2 id="typeorm에서-n--1-을-해결하는-방법">TypeORM에서 N + 1 을 해결하는 방법</h2>
<ol>
<li><code>find</code> 메서드에 <code>relations</code> 옵션을 적용하는 방법</li>
<li><code>QueryBuilder</code>를 사용하는 방법</li>
<li>entity를 수정하는 방법</li>
<li>쿼리를 나눠서 실행하는 방법<ul>
<li>추가적인 쿼리의 실행으로 DB hit은 증가되지만, N+1의 문제는 해결할 수 있다.</li>
</ul>
</li>
</ol>
<p>코파일럿으로 해결법을 찾았을 때 쿼리빌더를 알려줬음. =&gt; 복붙해서 적용했는데 해결이 안됐던 원인이 뭐지? -&gt; 이건 그냥 아직까진 ai따위가 개발자를 대체할 수 없다는 증거로 생각함 ^^.</p>
<p>단 한번의 DB 호출로 원하는 데이터를 가져올 수 있다면 best지만, N+1 문제가 발생할 수 있는 경우, (혹은 많은 부하가 걸리는 작업일 경우) 나눠서 호출하는 것도 하나의 방법이다.</p>
<p>역시
완벽한 해결책은 없나보다. 모든 것이 트레이드 오프인걸까 🤔</p>
]]></description>
        </item>
        <item>
            <title><![CDATA["추상화"라는 개념이 난 왜이렇게 어렵지?]]></title>
            <link>https://velog.io/@i-can-do/%EC%B6%94%EC%83%81%ED%99%94%EB%9D%BC%EB%8A%94-%EA%B0%9C%EB%85%90%EC%9D%B4-%EB%82%9C-%EC%99%9C%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%96%B4%EB%A0%B5%EC%A7%80</link>
            <guid>https://velog.io/@i-can-do/%EC%B6%94%EC%83%81%ED%99%94%EB%9D%BC%EB%8A%94-%EA%B0%9C%EB%85%90%EC%9D%B4-%EB%82%9C-%EC%99%9C%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%96%B4%EB%A0%B5%EC%A7%80</guid>
            <pubDate>Sun, 27 Oct 2024 07:55:57 GMT</pubDate>
            <description><![CDATA[<p>전 직장에서 NestJS를 사용해서 프로젝트를 진행했다.
<strong>NestJS는 OOP 원칙을 기반으로 하는 프레임워크</strong>이다.</p>
<p>객체 지향 설계 원칙들 중 하나인 
<strong>의존 관계 역전 원칙</strong>(Dependency Inversion Principle : DIP)
: 이 원칙은 <strong>고수준 모듈이 저수준 모듈에 직접 의존하지 않도록, 추상화된 인터페이스에 의존하도록 하는 원칙</strong>이다. 이렇게 함으로써 <strong>확장성과 유연성이 높아지고 코드 수정 없이도 새로운 기능 추가가 가능하다</strong>는 장점이 있다.</p>
<p>여기서 DIP의 개념은 이해를 했는데, 추상화라는 개념이 머릿속에 정립되지 않아서 또 검색했다.
추상화라는 개념이 등장할 때 마다 구글링을 하고 있는 게 너무 귀찮다.
그만 검색하길 바라며 추상화에 대해 간략하게 정리하고 넘어가자</p>
<p>먼저 추상화의 반대 개념은 구체화라고 할 수 있다.
<strong>추상화</strong>는 <em>중요한 기능에만 초점을 맞추고 세부 사항들을 감추는 것.</em>
<strong>구체화</strong>는 <em>숨겨진 세부사항까지 드러내서 구현에 집중하는 것.</em></p>
<p>이제까지 작성했던 인터페이스나 추상 클래스를 생각해보자 🤔
공통적인 부분만 뽑아내고 세부적인 사항들은 감춰서 하나의 인터페이스를 만들었다.
그렇다면 추상화란 중요한 부분을 강조하기 위해 덜 중요한, 불필요한 세부적 사항들은 제거해서 단순하게 만드는 개념이라고 생각할 수 있다.</p>
<p>이렇게 추상화된 인터페이스를 상속받아서 구체화된 클래스를 구현했었다.</p>
<blockquote>
<p>Good 잊지말자
<strong>추상화</strong>란, <strong>공통적인 부분만 뽑아내고 세부적인 사항들은 감춰서 단순하게 만드는 개념</strong>이다</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우먼테크] 잇(IT)생을 고민하는 개발자편]]></title>
            <link>https://velog.io/@i-can-do/%EC%9A%B0%EB%A8%BC%ED%85%8C%ED%81%AC-%EC%9E%87IT%EC%83%9D%EC%9D%84-%EA%B3%A0%EB%AF%BC%ED%95%98%EB%8A%94-%EA%B0%9C%EB%B0%9C%EC%9E%90%ED%8E%B8</link>
            <guid>https://velog.io/@i-can-do/%EC%9A%B0%EB%A8%BC%ED%85%8C%ED%81%AC-%EC%9E%87IT%EC%83%9D%EC%9D%84-%EA%B3%A0%EB%AF%BC%ED%95%98%EB%8A%94-%EA%B0%9C%EB%B0%9C%EC%9E%90%ED%8E%B8</guid>
            <pubDate>Thu, 24 Oct 2024 23:48:46 GMT</pubDate>
            <description><![CDATA[<p>어쩌다 운 좋게 &quot;2024 우먼 테크 세미나&quot;를 알게 되었고, 8월부터 진행되었던 것 같은데 아쉽게도 앞부분은 놓쳤고 후반부 2주 정도만 참석할 수 있었다. 
사실 살면서 세미나라는 곳에 처음 가봤는데, 너무나도 값진 경험이었다👍</p>
<p>어떤 개발자가 되어야 할지, 내가 꿈꾸는 개발자 상과 되고 싶은 리더의 모습에 대해 막연하게만 생각해왔던 나에게 당근마켓, 원티드랩, 카카오뱅크, 마이크로소프트 등에서 일하는 선배 개발자들의 이야기는 큰 자극이 되었다. 그들의 이야기를 들으며 가슴이 뛰었고, 나도 언젠가 저분들처럼 되고 싶다는 열망과 좋은 영감을 얻을 수 있었다. 
게다가 개발자분들이 어쩜 그렇게 말도 잘하시는지, 너무 멋있었다!!!😍</p>
<p>앞으로 기회가 된다면 유료 세미나에도 적극적으로 참여해서 더 많은 배움을 얻고 싶다. 
정말 귀감이 되고 영감이 되는 세미나였다.
아래는 개인적으로 세미나에서 기억에 남았던 내용들을 정리해봤다.</p>
<ul>
<li><p>말 안하면 모른다 내 밥그릇은 내가 챙기는 겁니다.</p>
</li>
<li><p>하고 싶은 게 많다는 건 복이다. 
나에게 줄 수 있는 변화이고, 내 스스로가 미래를 기대한다는 뜻이다.</p>
</li>
<li><p>포트폴리오는 나에게 집중하는 게 아니라 남에게 집중해서 작성해야한다.
&quot;이런 사람입니다&quot;가 아니라 &quot;이런 사람 필요하시죠?&quot;</p>
</li>
<li><p>내가 그 사람을 부러워하는 이유를 찾고 그 사람을 모방해라. 그럼 나의 것이 된다.</p>
</li>
<li><p>1인분의 몫을 하고 난 다음에는, 스스로 문제를 직접 발굴할 수 있는 능력이 필요하다.</p>
</li>
<li><p>인지하지 못하는 문제를 찾아내고 어떻게 해야할까 계획을 할 수 있어야 하며 실행에 옮겨야한다.</p>
</li>
<li><p>투명하게 공유하는 습관이 중요하다.</p>
</li>
<li><p>앞으로 나는 팀에서, 사람과 일에 어떤 영향을 끼쳐야할까 고민해라.</p>
</li>
<li><p>우리 팀에 부족한 영향을 파악하는 것이 성장의 시작이다.</p>
</li>
<li><p>프로젝트가 끝나고 나서 시니어가 잊지 말아야할 가장 중요한 일은 회고다. 
조금 더 잘할 수 있는 방법이 있지 않았나? 곱씹으며 팀의 성과를 기록해라.</p>
</li>
<li><p>&quot;North Star&quot;, &quot;Path Finder&quot; 길잡이가 시니어의 역할이다.</p>
</li>
<li><p>연차보다는 next level을 기대하게 되는 사람이 시니어다.</p>
</li>
<li><p>개발을 하는 사람과 일을 하는 사람</p>
</li>
<li><p>시니어는 혼자 결정하는 사람이 아니다. 혼자 해버리면 팀의 병목이 되버린다.</p>
</li>
<li><p>일관성 있게 예측 가능한 시니어.</p>
</li>
<li><p>방법보다는 방향을 제시하는 사람.</p>
</li>
<li><p>팀원의 불편함을 해결해주는 사람.</p>
</li>
<li><p>마이크로매니징은 금물이다. 🙅🏻‍♀️</p>
</li>
<li><p>backbone있는 리더
반대하되 수용하라.
동의할 수 없는 결정에 대해 정중하게 이의제기할 의무가 있다.</p>
</li>
<li><p>자주 바뀌는 결정에 대해서는 의사결정권을 요구하는 것도 방법이다.</p>
</li>
<li><p>내가 원할 때 해당 직무를 맡아야 흥미가 생긴다.</p>
</li>
<li><p>일이 벅차다면 내가 하고 있는 일에 얼마의 시간을 사용하고 있는 지 리스트업해보기.
분석해보면 생각보다 시간을 덜 쓰고 있을 수도 있고,
시간을 너무 많이 사용하고 있다면 내가 하지 않아도 되는 일을 다른 사람에게 넘기는 것도 방법이다.</p>
</li>
<li><p>팀원들이 출근하기 전, 오전에는 내 일을 하고 오후에는 팀원들에게 열어둔다.</p>
</li>
<li><p>생각보다 많이 중요한 커뮤니케이션 스킬.</p>
</li>
<li><p>모든 걸 리뷰하는 슬랙 채널 만들기.
궁금한 건 무엇이든 물어보는 채널이다.
팀원들이 이런 걸 물어봐도 되나 망설이는 게 보이면, 리더가 먼저 자유롭게 질문을 던져야한다.
그렇게 팀 문화를 만들어 나가는 게 중요하다.</p>
</li>
<li><p>되게 방어적이고 의사소통이 안되고, 자기 고집을 내세우는 이기적인 사람과 어떻게 협업할 수 있을까
역으로 본인의 오너십을 이용해라. 본인이 직접 주도하게끔 환경을 만들고, 증거를 모아라.</p>
</li>
</ul>
<p>이직을 준비하면서 &#39;어떤 개발자가 되어야 할까&#39;, &#39;내가 되고 싶은 개발자의 모습은 무엇일까&#39; 막연하게만 생각했었는데 세미나를 들으면서 많은 영감을 얻을 수 있어 참 좋았다.
앞으로도 이런 기회가 더 많아지면 좋겠다.</p>
<p>자, 이제 기술면접 공부하러 가자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[최고의 복지는 좋은 동료(feat. Java는 잠시 접어둬)]]></title>
            <link>https://velog.io/@i-can-do/%EC%B5%9C%EA%B3%A0%EC%9D%98-%EB%B3%B5%EC%A7%80%EB%8A%94-%EC%A2%8B%EC%9D%80-%EB%8F%99%EB%A3%8Cfeat.-Java%EB%8A%94-%EC%9E%A0%EC%8B%9C-%EC%A0%91%EC%96%B4%EB%91%AC</link>
            <guid>https://velog.io/@i-can-do/%EC%B5%9C%EA%B3%A0%EC%9D%98-%EB%B3%B5%EC%A7%80%EB%8A%94-%EC%A2%8B%EC%9D%80-%EB%8F%99%EB%A3%8Cfeat.-Java%EB%8A%94-%EC%9E%A0%EC%8B%9C-%EC%A0%91%EC%96%B4%EB%91%AC</guid>
            <pubDate>Fri, 11 Oct 2024 03:41:50 GMT</pubDate>
            <description><![CDATA[<p>오랜만에 전 직장 동료들을 만났다.
5월 말에 권고 사직을 당했지만 아직까지 밀린 월급을 못받은 상태라 속이 많이 쓰리다.</p>
<p>그럼에도 보고 싶던 동료들🥹</p>
<p>사람 스트레스없이 일할 수 있다는 건 최고의 복지라고 생각한다.
또 그런 회사를 가고 싶다. 
그런 회사가 아니라면 내가 만들어야지!!</p>
<p>9월부터 본격적으로 이직을 준비했지만 2년전에 비해 채용 공고가 엄청 줄어들었다.
그래서 Java를 공부하고 있었는데 동료들을 만나고 나니 생각이 다시 바뀌었다.</p>
<p>신기능에 대해서 어떻게 개발하면 좋을지 기술 검토하고,
갑자기 발생한 배포 이슈에 밤 12시까지 로그 추적하면서 마이그레이션 풀고,
왜 코드를 이렇게 작성했을까 감히 사수분 코드에 대해 토를 달아보기도 했었고,
푸시 딜레이 문제로 몇일이 뭐야 몇주? 몇달을 디버깅했지만 도저히 모르겠어서 스택오버플로우에 첫 문의글도 남겨보고,
어떻게 그리고 왜 그렇게 개발해야하는 건지 이해가 안가서 클라분들 미간 찌푸려질때까지 눈치보면서 계속 물어보고,
나는 다르게 생각한다며 서로 자기 의견이 맞다는 걸 입증하려고 관련 자료 찾아보고,
잦은 야근에 다들 신경이 곤두서있기도 했고,
그렇게 많은 우여곡절을 지나 배포된 버전을 유저들이 좋아하고 잘 쓸 때 느꼈던 성취감과 재미.</p>
<p>다시 느끼고 싶다 도파민 🔥
일하고 싶다 !!!!</p>
<p>서류에서 떨어진다면 이력서를 수정해야하는데
서류에서 떨어진다고 Java를 공부하고 있다니 이건 잘못된 방향이였다.</p>
<p>Java는 잠시 접어두고 이력서부터 수정해야겠다.</p>
<p>오늘은 취업을 위한 우먼테크 세미나 일정도 있고,
남은 이번주 이력서 열심히 수정한 다음에 
다음주부터 직장 동료들, 지인들 총 동원해서 피드백을 받아야겠다.</p>
<p>서류에서 계속 떨어져서 피드백을 받아보고 싶다고 했을 때 너도 나도 기꺼이 도와주겠다던 사람들.
너무 감사하다.</p>
<p>도와주겠다는 사람들이 주위에 있다는 것
그것도 나의 능력이 아니겠는가~
제대로 뽕 좀 뽑아봐야겠다 😋</p>
<p>든든하니 즐거웠고 유익했던 자리였다.
다들 어디서 무엇을 하든 잘되면 좋겠다 !!! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[[Java]] long으로 선언하고 123,456,789,123,456,789를 할당했는데 "Integer number too large" 라니요?]]></title>
            <link>https://velog.io/@i-can-do/Java-long%EC%9C%BC%EB%A1%9C-%EC%84%A0%EC%96%B8%ED%95%98%EA%B3%A0-123456789123456789%EB%A5%BC-%ED%95%A0%EB%8B%B9%ED%96%88%EB%8A%94%EB%8D%B0-Integer-number-too-large-%EB%9D%BC%EB%8B%88%EC%9A%94</link>
            <guid>https://velog.io/@i-can-do/Java-long%EC%9C%BC%EB%A1%9C-%EC%84%A0%EC%96%B8%ED%95%98%EA%B3%A0-123456789123456789%EB%A5%BC-%ED%95%A0%EB%8B%B9%ED%96%88%EB%8A%94%EB%8D%B0-Integer-number-too-large-%EB%9D%BC%EB%8B%88%EC%9A%94</guid>
            <pubDate>Mon, 07 Oct 2024 03:40:47 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.inflearn.com/course/lecture?courseSlug=%EC%A0%9C%EB%8C%80%EB%A1%9C-%ED%8C%8C%EB%8A%94-%EC%9E%90%EB%B0%94&amp;unitId=157973&amp;subtitleLanguage=ko">제대로 파는 얄코의 자바 강의</a>를 듣다가, 이제까지 본 적 없는 이상한 코드를 발견했다.</p>
<pre><code>//  ⭐ int의 범위를 벗어나는 수에는 리터럴에도 명시 필요
//  끝에 l 또는 L을 붙여 볼 것
long _8b_long1 = 123456789123456789;  
long _8b_long2 = 123_456_789_123_456_789L; </code></pre></br>

<h2 id="🤔-what-the-l">🤔 <strong>What the &quot;L&quot;?</strong></h2>
<pre><code>Java7부터는 가독성을 위해 long _8b_long2 처럼 숫자 사이에 언더바를 사용할 수 있다.</code></pre><p>자바의 정수 자료형에는 4가지가 있다.</p>
<ol>
<li>byte (1바이트)</li>
<li>short (2바이트)</li>
<li>int (4바이트)</li>
<li>long (8바이트)</li>
</ol>
</br>

<p><strong>long</strong>으로 <code>_8b_long1</code> 변수를 선언 및 초기화했으니까,
<strong>-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807</strong> 까지 
저장이 가능할 것이라 예상했지만</p>
<p><img src="https://velog.velcdn.com/images/i-can-do/post/6db05f8d-7bfe-498b-b7d2-49ed0d5641ec/image.png" alt=""></p>
<p>위 스크린샷처럼 &quot;Integer number too large&quot; 라는 컴파일 오류가 떴다.?
강의에서는 <span style="color: blue;">long 자료형에 값을 대입할 때는 리터럴(값) 뒤에 소문자나 대문자 L을 붙여야
long으로 인식한다</span>고 짧게 설명하고 넘어가길래, 왜 L을 별도로 붙여야하나 궁금해서 찾아봤다.</p>
<p><span style="color: red;">Java는 기본적으로 모든 정수를 int형으로 나타낸다.</span></p>
<p><span style="color: red;"><strong>Java는 값을 변수에 저장하기 전에, 값을 먼저 메모리에 저장</strong>한다. 이때 저장하는 형태가 <strong>무조건 int형</strong>으로 되어있다. 이 때, 값 맨 뒤에 대문자 L을 붙여주면, Java가 int형이 아닌 long형으로 저장하게 된다고 한다. </span></p>
</br>
왜 굳이 기본값을 int로 저장할까 궁금해서 gpt에게 물어봤더니 2가지 이유가 있다고 한다.
아직 100% 이해는 못했지만, 나중에라도 다시 찾아보기 위해 같이 기록하고 넘어간다.

<pre><code>1. 성능 최적화: 대부분의 CPU가 32비트 정수를 빠르게 처리할 수 있다.
2. 메모리 절약: 많은 프로그램에서 int 크기(32비트)의 숫자로 충분하다. </code></pre></br>
</br>

<h2 id="-추가-내용">+ 추가 내용</h2>
<p>강의 후반부에 나온 추가 설명 덧붙이기</p>
<pre><code>byte b1 = 1;
byte b2 = 2;
short s1 = 1;
short s2 = 2;

//  ⚠️ 아래는 모두 불가
byte b3 = b1 + b2;
short s3 = b1 + b2;
short s4 = b1 + s2;
short s5 = s1 + s2;

//  ⭐ byte와 short의 연산들은 int 반환
//  그냥 int를 많이 쓰는 이유 중 하나
int i1 = b1 + b2;
int i2 = s1 + s2;
int i3 = b1 + s1;

long l1 = 1;
long l2 = 2;

// long끼리의 연산은 long 반환
long l3 = l1 + l2;</code></pre><p><span style="color: red;">b1 + b2의 결과를 byte에 넣을 수 없고, byte보다 큰 자료형인 short에도 넣을 수 없다.
<strong>byte와 short의 연산 결과들은 결과값으로 int를 반환</strong>하기 때문이다.
메모리를 크~게 절약해야 할 상황이 아닌 이상 <strong>int를 많이 사용</strong>한다.</span>
</br></p>
<p>** 참고자료</p>
<p><a href="https://blog.naver.com/suboo00/220615372698">[블로그] 3-2 접미사 L, F</a>
<a href="https://www.inflearn.com/course/lecture?courseSlug=%EC%A0%9C%EB%8C%80%EB%A1%9C-%ED%8C%8C%EB%8A%94-%EC%9E%90%EB%B0%94&amp;unitId=157973&amp;subtitleLanguage=ko">[강의] 제대로 파는 자바 by 얄코</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JDK, JRE, JVM ?]]></title>
            <link>https://velog.io/@i-can-do/JDK-JRE-JVM</link>
            <guid>https://velog.io/@i-can-do/JDK-JRE-JVM</guid>
            <pubDate>Sun, 06 Oct 2024 04:43:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/i-can-do/post/b7d96b5f-8c7a-49cb-b818-9cc7c89ec153/image.png" alt=""></p>
<h2 id="🤖-jvmjava-virtual-machine">🤖 JVM(Java Virtual Machine)</h2>
<p>Java로 작성된 모든 프로그램은 JVM에서만 실행이 되기 때문에 
자바를 실행하려면 JVM이 반드시 설치되어 있어야 한다.</p>
<p>프로그래밍 언어에는 </p>
<ol>
<li><strong>번역</strong>본을 만들어서 컴퓨터에게 전달하는 <strong>컴파일 언어</strong>와,</li>
<li>실시간 <strong>통역</strong>을 통해 컴퓨터에게 전달하는 <strong>인터프리터 언어</strong>가 있다.<blockquote>
</blockquote>
번역과 통역이 필요한 이유? 
: 사람이 입력한 코드를 컴퓨터가 이해할 수 있도록 바이너리 코드(기계어)로 변환해야 하기 때문이다.</li>
</ol>
<p>여기서 <strong>C언어와 Java</strong>는 <strong>컴파일 언어</strong>(번역)에 속한다.</p>
<p>개발자가 작성한 소스 코드를 컴파일러가 각 기계가 이해하는 기계어로 변환해서 실행 프로그램(exe)를 만들어주는 데, 이 <strong>기계어는 특정 OS나 CPU 구조에 맞춰진 컴파일러에 의해 다르게 컴파일 되는 특성</strong>이 있다. === <strong>다른 OS, CPU 구조를 가진 환경에서는 이 기계어를 이해할 수 없다</strong>는 뜻 !!</p>
<p>이에 따라서 C언어는, 윈도우 OS 환경에서 컴파일된 코드를 리눅스 OS에서는 읽어들일 수 없었다. 
<strong>개발자가 직접 윈도우용 C 프로그램, 리눅스용 C 프로그램을 각각 만들어야하기 때문에, 
C언어의 특징으로 운영 체제에 종속된 언어 &amp; 이식성이 낮은 언어</strong>라고 한다.
<img src="https://velog.velcdn.com/images/i-can-do/post/92647698-28ae-4945-80a1-57353f7f2ec2/image.png" alt=""></p>
<p>하지만 <strong>Java 언어</strong>로 작성된 코드는, C언어처럼 직접 운영체제에서 실행되는 게 아니고, <span style="color:red"> 
<strong>중간에 JVM을 사용하여 JVM이 컴파일된 코드와 하드웨어 OS 중간에서 각 환경에 맞게 바이트 코드로 변환</strong>해준다. 
이로 인해 각 OS 환경에 맞게 컴파일러가 이해할 수 있도록 직접 변경이 필요했던 과정이 사라지고,
<strong>모든 플랫폼에 제약없이 동작할 수 있다</strong>는 장점</span>이 생겼다.
<img src="https://velog.velcdn.com/images/i-can-do/post/c3b3375f-1ab8-42f7-bf1f-15f6ce689e23/image.png" alt=""></p>
<p><span style="color:blue"> 반면 C언어와 다르게,
  <strong>JVM 이라는 한 단계를 더 거치기 때문에 상대적으로 느린 실행 속도가 단점</strong>이 된다(컴파일 과정이 2번 필요함).</span></p>
<p>Java로 작성된 프로그램은 .class 라는 확장자를 가진 파일로 변환이 된다.
변환된 .class 파일은 JVM 위에서 작동이 된다.
</br></p>
<h2 id="🤖-jrejava-runtime-environment">🤖 JRE(Java Runtime Environment)</h2>
<p>자바 실행 환경의 약자이다.</p>
<p>JRE는 Java Class Loader, Java Class Libraries, JVM을 포함한다.
    - Java Class Loader: 필요한 클래스들을 JVM 위로 올려주는 역할
    - Java Class Libraries: 자바를 실행시키는 데 필수적인 라이브러리</p>
<p><strong>JRE는 개발에 사용되는 것이 아닌 실제 프로그램을 구동시키는 데 집</strong>중을 하고 있다.</p>
<p><strong>Java Compiler를 비롯한 개발에 필요한 요소들은 없기</strong> 때문에, 
Java 코드가 주어져도 이를 분석하거나 클래스 파일로 변환하는 일은 JRE가 할 수 없다.</p>
</br>

<h2 id="🤖-jdkjava-development-kit">🤖 JDK(Java Development Kit)</h2>
<p>개발자들이 Java를 이용하여 프로그램을 개발할 때 사용하는 SDK(Software Development Kit)이다. </p>
<p>JDK를 설치하면 JRE, JVM이 자동으로 같이 설치되며,
JRE와는 별도로 컴파일러(javac), 디버깅(jdb), 문서 생성기(javadoc), 아카이버(jar) 같은 도구들이 갖추어져 있다.</p>
</br>
</br>
</br>

<h4 id="참고자료">참고자료</h4>
<p><a href="https://inpa.tistory.com/entry/JAVA-%E2%98%95-JDK-JRE-JVM-%EA%B0%9C%EB%85%90-%EA%B5%AC%EC%84%B1-%EC%9B%90%EB%A6%AC-%F0%9F%92%AF-%EC%99%84%EB%B2%BD-%EC%B4%9D%EC%A0%95%EB%A6%AC">[블로그] JDK / JRE / JVM 개념 &amp; 구성 원리 💯 총정리</a></p>
<p><a href="https://www.inflearn.com/course/lecture?courseSlug=%EC%A0%9C%EB%8C%80%EB%A1%9C-%ED%8C%8C%EB%8A%94-%EC%9E%90%EB%B0%94&amp;unitId=157952&amp;subtitleLanguage=ko">[인프런] 제대로 파는 자바 - 자바는 어떤 언어인가요? (+JVM, JRE, JDK) by 얄코</a></p>
<p><a href="https://tecoble.techcourse.co.kr/post/2021-07-12-jvm-jre-jdk/">[블로그] Tecoble - JVM에 관하여</a></p>
<p><a href="https://steady-coding.tistory.com/305#google_vignette">[블로그] JVM 메모리 구조란? (JAVA)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[새로운 자극이 필요해,,]]></title>
            <link>https://velog.io/@i-can-do/%EC%83%88%EB%A1%9C%EC%9A%B4-%EC%9E%90%EA%B7%B9%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%B4</link>
            <guid>https://velog.io/@i-can-do/%EC%83%88%EB%A1%9C%EC%9A%B4-%EC%9E%90%EA%B7%B9%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%B4</guid>
            <pubDate>Fri, 04 Oct 2024 08:30:08 GMT</pubDate>
            <description><![CDATA[<p>1년 6개월이라는 경력도 애매하고,
많은 스타트업들이 망해서 그런가 Node개발자를 뽑는 채용공고가 너무 없다.
나도 300개, 400개 무지성으로 지원하고 싶은데 그게 안된다.
난 정말 &quot;재미&quot;가 중요한 사람인가보다. 
재밌는 서비스를 만들고 싶다.
회사의 서비스, 방향성에 공감하지 못하면 지원서도 안넣고 있다.
그렇게 회사를 고르다 보니 이력서를 넣을 곳이 없다 ㅠㅠ
가령 찾았다고 해도, 자격요건의 java가 계속 발목을 붙잡는다.</p>
<p>일주일간 고민을 많이 했는데, 그래도 실업급여는 내년 1월까지고.
리눅스마스터를 따려고 했지만 시험일정이 올해는 끝났고.
매일 공고를 보고는 있지만 Node는 없고.
그래, 백엔드는 결국 JAVA라는 말도 있지 않는가
자바를 배워야겠다.
가자 스프링으로~~ </p>
<p>그렇게 인프런 강의를 결제했다.
부트캠프를 한번 더 다닐까 고민했지만(자바 강의가 무료고, 들어가면 팀프로젝트도 가능하니까) 
몇개월씩 걸리는 부트캠프는 심적 부담이 된다. 
시작해보자 자바 스터디,
그래도 개발했던 경험이 있으니까 많이 어렵진 않을꺼야
할쑸다!!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[VScode에서 auto fix eslint on save 설정하는 방법]]></title>
            <link>https://velog.io/@i-can-do/VScode%EC%97%90%EC%84%9C-auto-fix-eslint-on-save-%EC%84%A4%EC%A0%95%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@i-can-do/VScode%EC%97%90%EC%84%9C-auto-fix-eslint-on-save-%EC%84%A4%EC%A0%95%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Tue, 03 Sep 2024 07:01:52 GMT</pubDate>
            <description><![CDATA[<ol>
<li>view -&gt; command palette</li>
<li>Preferences: Open User Settings(json) 선택</li>
<li>아래 코드 추가<pre><code>&quot;[typescript]&quot;: {
&quot;editor.formatOnSave&quot;: true,
&quot;editor.defaultFormatter&quot;: &quot;esbenp.prettier-vscode&quot;
},</code></pre></li>
</ol>
<p><a href="https://stackoverflow.com/a/76241488">참고자료</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD 오답노트]]></title>
            <link>https://velog.io/@i-can-do/SQLD-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@i-can-do/SQLD-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Tue, 20 Aug 2024 15:05:47 GMT</pubDate>
            <description><![CDATA[<h4 id="데이터-모델링의-3단계추상화-수준에-따라-나뉜다">데이터 모델링의 3단계(추상화 수준에 따라 나뉜다)</h4>
<ol>
<li>개념적 데이터 모델링(먼저 진행함): 추상화 수준이 높고 업무 중심적, 포괄적인 수준의 모델링 진행, 전사적 데이터 모델링</li>
<li>논리적 데이터 모델링: 시스템으로 구축하고자 하는 업무에 대해 key, 속성, 관계 등을 정확하게 표현, 재사용성이 높음</li>
<li>물리적 데이터 모델링: 실제로 데이터베이스에 이식할 수 있도록 성능, 저장 등 물리적인 성격을 고려하여 설계</li>
</ol>
<h4 id="속성">속성</h4>
<p>속성의 특성에 따른 분류 : 기본속성, 파생속성, 설계속성
구성방식에 따른 분류 : PK, FK, 일반속성</p>
<h4 id="주식별자의-특징">주식별자의 특징</h4>
<ol>
<li>유일성: 주식별자에 의해 엔터티 내에 모든 인스턴스들을 유일하게 구분한다.</li>
<li>최소성: 주식별자를 구성하는 속성의 수는 유일성을 만족하는 최소의 수여야 한다.</li>
<li>불변성: 주식별자가 특정 엔터티에 지정되면, 그 값은 변하지 않아야 한다.</li>
<li>존재성: 주식별자가 정해지면 값이 꼭 정해져야한다.(NOT NULL)</li>
</ol>
<h4 id="실행순서">실행순서</h4>
<p>FROM-WHERE-GROUP BY-HAVING-SELECT-ORDER</p>
<h4 id="truncate">TRUNCATE</h4>
<p>TRUNCATE는 테이블의 모든 행(row)의 데이터를 삭제한다. DDL에 속함
    - 참고) DROP은 테이블 정의 자체를 삭제한다.
또 다른 DDL : CREATE, ALTER, DROP</p>
<h4 id="함수">함수</h4>
<p>LPAD(&#39;X&#39;, 5, &#39;X&#39;) =&gt; XXXXX : 총 다섯자리를 &#39;X&#39;로 채운다.
ROUND(12345.678, -2) =&gt; 십의자리에서 반올림하여 12300
SIGN(120) =&gt; 양수면 1, 음수면 -1, 0이면 0을 반환한다.</p>
<h4 id="null-관련-함수들">NULL 관련 함수들</h4>
<p>COMM
NULL
500</p>
<p>NVL(COMM, 100), ISNULL(COMM, 100) : 100, 500</p>
<ul>
<li>COMM이 NULL이면 2번째 지정값을 출력하고 NULL이 아니면 COMM을 그대로 출력한다.</li>
</ul>
<p>NULLIF(COMM, 100) : NULL, 500</p>
<ul>
<li>COMM와 100이 같으면 NULL을 리턴하고 다르면 첫 번째 값을 반환한다.</li>
</ul>
<p>COALESCES(COMM, 100) : 100, 500</p>
<ul>
<li>NULL이 아닌 첫번째 값을 반환한다.</li>
</ul>
<p>DECODE(A, B, X, Y) </p>
<ul>
<li>A=B 이면 X, A !=B 이면 Y 출력</li>
</ul>
<h4 id="시간-계산">시간 계산</h4>
<p>30/24/60은 30x1/24/60으로 생각하자. 1일을 24시간으로 나누면 1시간이고 1시간을 60으로 나누면 1분이다.</p>
<h4 id="논리연산자-실행-순서">논리연산자 실행 순서</h4>
<p>NOT &gt; AND &gt; OR</p>
<h4 id="집계함수와-null">집계함수와 NULL</h4>
<p>SUM(NULL)은 NULL을 리턴하고
COUNT(NULL)은 0을 리턴한다.</p>
<h4 id="중복-순위-처리">중복 순위 처리</h4>
<p>RANK는 2등이 2명일 경우 1,2,2,4
DENSE_RANK는 2등이 2명일 경우 1,2,2,3</p>
<h4 id="데이터-형식">데이터 형식</h4>
<p>NUMBER(5,2)는 XXX.YY 로 표현되야 한다. XXXX.Y는 불가함! 소수는 숫자가 더 많아져도 OKAY
CHAR(10)으로 컬럼이 정의되어 있을 때 NULL값은 들어갈 수 있다.</p>
<h4 id="기타">기타</h4>
<p>COUNT를 사용할 때 CASE ~ ELSE 0가 있으면 안된다.</p>
<p>OR는 중복을 1번만 카운트한다.</p>
<p>GROUP BY 절에는 컬럼 별칭 사용 불가, 그룹 합수도 사용 불가하다.</p>
<p>별칭을 사용했으면 별칭으로 정렬해야한다.(테이블.별칭 사용 불가)</p>
<p>&lt;= ALL(20,30,40)은 20,30,40보다 작은 값을 구하는 것이니 20보다 작은 수를 찾으면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인앱결제 구독 기능 서버 구현]]></title>
            <link>https://velog.io/@i-can-do/%EC%9D%B8%EC%95%B1%EA%B2%B0%EC%A0%9C-%EA%B5%AC%EB%8F%85-%EA%B8%B0%EB%8A%A5-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@i-can-do/%EC%9D%B8%EC%95%B1%EA%B2%B0%EC%A0%9C-%EA%B5%AC%EB%8F%85-%EA%B8%B0%EB%8A%A5-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Wed, 07 Aug 2024 00:19:41 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/i-can-do/post/f4e7a343-e82a-4208-946f-367df6cc1f67/image.png" alt=""></p>
<h3 id="애플-정기-결제-신규-구매-처리">애플 정기 결제 신규 구매 처리</h3>
<ol>
<li>결제 정보 수신<ul>
<li>유저가 앱에서 정기 결제 상품을 구매하면, 클라이언트는 결제 정보를 서버로 전송한다.</li>
<li>ex: <code>originalTransactionId</code> 등</li>
</ul>
</li>
<li>결제 정보 검증<ul>
<li>서버는 클라이언트로부터 받은 결제 정보를 애플 서버로 보내 검증한다.</li>
<li><code>https://api.storekit.itunes.apple.com/inApps/v1/subscriptions/${originalTransactionId}</code></li>
</ul>
</li>
<li>응답 데이터 처리:<ul>
<li>애플 서버는 암호화된 응답을 반환한다.</li>
<li>디코딩하여 필요한 유저의 구매 정보를 추출한다.</li>
</ul>
</li>
<li>구매 정보 저장 및 제공:<ul>
<li>디코딩한 정보를 기반으로 유저의 구매 정보를 저장하고 구매한 상품을 유저에게 제공한다.</br> 

</li>
</ul>
</li>
</ol>
<h3 id="애플-정기-결제-상품-관리">애플 정기 결제 상품 관리</h3>
<ol>
<li>실시간 알림 수신:<ul>
<li>앱스토어가 구독 상품의 상태가 변경될 때마다(ex: 갱신, 결제 실패 등) 실시간 알림을 서버로 보내준다. </li>
<li>알림을 받기 위한 서버 URL을 애플 사이트에 등록해야한다.</li>
</ul>
</li>
<li>알림 데이터 처리:<ul>
<li>실시간 알림은 암호화되어 있으므로 이를 디코딩해야한다.</li>
<li>디코딩한 데이터에서 필요한 정보를 추출하여 구매 정보로 저장한다.</li>
</ul>
</li>
<li>구독 상태 관리:<ul>
<li>실시간 알림을 통해 구독 상태를 관리하고, 필요시 유저에게 결제 상품을 제공한다.</li>
<li>신규 구독에 대해서는 클라이언트가 보내주는 데이터를 기반으로 처리하며, 기타 상태 변경은 실시간 알림 기반으로 처리하도록 구현함.</br> 

</li>
</ul>
</li>
</ol>
<h3 id="구글-정기-결제-신규-구매-처리">구글 정기 결제 신규 구매 처리</h3>
<ol>
<li>결제 정보 수신:<ul>
<li>유저가 앱에서 정기 결제 상품을 구매하면, 클라이언트는 결제 정보를 서버로 전송한다.</li>
<li>ex: <code>token</code>, <code>packageName</code> 등</li>
</ul>
</li>
<li>결제 정보 검증:<ul>
<li>서버는 클라이언트로부터 받은 결제 정보를 구글 서버로 보내 정기 결제 여부를 검증한다.</li>
<li><code>https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${packageName}/purchases/subscriptionsv2/tokens/${token}</code></li>
</ul>
</li>
<li>구매 처리:<ul>
<li>구글 서버에서 받은 응답 데이터를 사용하여 <a href="https://developer.android.com/google/play/billing/integrate?hl=ko#process">구매 처리</a> 를 진행한다.</li>
<li><code>https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}:acknowledge</code></li>
</ul>
</li>
<li>구매 정보 저장 및 제공:<ul>
<li>2번에서 받은 응답 데이터 중 필요한 유저의 구매 정보를 저장하고, 구매한 상품을 제공한다.</br> 

</li>
</ul>
</li>
</ol>
<h3 id="구글-정기-결제-상품-관리">구글 정기 결제 상품 관리</h3>
<ol>
<li>알림 시스템(Pub/Sub) 설정:<ul>
<li>구글의 Pub/Sub 서비스를 통해 구독 상태 변경 알림을 수신한다.<pre><code>  - 구독자의 엔드포인트로 구독 주제에 대한 메세지를 전송해주는 방식</code></pre></li>
<li>Push 방식과 Pull 방식이 있으며 Push 방식을 채택함<ul>
<li>Push 방식을 채택한 이유: 실시간 처리가 중요했으며, 이벤트가 발생하면 구글이 알아서 메시지를 보내주기 때문에 구현이 비교적 간편해 보였음.</li>
</ul>
</li>
</ul>
</li>
<li>알림 데이터 처리:<ul>
<li>Push 방식으로 받은 알림 데이터를 처리하여 구독 상태 변경을 관리한다.</li>
<li>필요한 데이터를 추출하여 유저의 구매 정보를 갱신한다.</li>
</ul>
</li>
<li>구독 상태 관리:<ul>
<li>실시간 알림을 통해 구독 상태를 관리하고, 필요시 유저에게 결제 상품을 제공한다.</li>
<li>신규 구독에 대해서는 클라이언트가 보내주는 데이터를 기반으로 처리하며, 기타 상태 변경은 실시간 알림 기반으로 처리하도록 구현함.</li>
</ul>
</li>
</ol>
</br> 

<h3 id="정리하다-보니-생각난-겪었던-에러사항-🔥">정리하다 보니 생각난, 겪었던 에러사항 🔥</h3>
<p>구글의 Pub/Sub 서비스를 사용하면서 동일한 구독 상품에 대해 테스트 환경(dev, stage)과 프로덕션 환경에 맞는 URL을 각각 입력하고 싶었지만 방법을 찾지 못해 어려움을 겪었던 게 기억난다. 애플은 애플은 샌드박스 환경이 별도로 제공되어 상대적으로 편리했지만, 구글의 경우 하나의 주제에 대해 하나의 구독만 가능했기에(내가 못찾았을 수도 있음) 테스트 환경에서의 정기 결제 이벤트 처리가 어려웠다.</p>
<p>이 문제를 해결하기 위해서 새로운 구독 상품도 만들어보고, 구글에 문의 사항도 제출해보았지만 테스트용 url을 추가로 입력할 수 없다는 답변을 받았었다. 추가 구독 상품을 만들려면 안드로이드 개발자의 시간도 필요했기에 과잉 개발로 판단하고 그만두게 되었다. </p>
<p>테스트가 필요한 경우, 실제 구독자의 갱신 날짜를 모두 계산하여 의존성 없는 시간대에 테스트 url로 수정 후 테스트를 진행했는데, 매우 불편하고 쫄리는(?) 경험이였다. 회사를 다니며 진행했던 가장 큰 프로젝트였다. 이때 구독상품뿐만 아니라 다양한 인앱상품도 같이 개발했는데 제대로된 상사의 피드백을 못받았기 때문에 다른 회사에서는 어떻게 처리하는지 매우 궁금하다.</p>
</br> 
</br> 
</br> 

<p>기억이 휘발되고 있어서 짧게 나마 정리해봤는데 정리하길 잘했두 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[NestJS에서 의존성 주입(Dependency Injection)을 구현하는 방법은?(feat. 제어의 역전)]]></title>
            <link>https://velog.io/@i-can-do/NestJS%EC%97%90%EC%84%9C-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85Dependency-Injection%EC%9D%84-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%80feat.-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84</link>
            <guid>https://velog.io/@i-can-do/NestJS%EC%97%90%EC%84%9C-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85Dependency-Injection%EC%9D%84-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%80feat.-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84</guid>
            <pubDate>Tue, 06 Aug 2024 05:29:34 GMT</pubDate>
            <description><![CDATA[<p align="center">
<img src = "https://velog.velcdn.com/images/i-can-do/post/4833d8a5-25dd-4ced-a3d5-26ae7ddac096/image.png" align="center">
</p>


<h3 id="nestjs에서-의존성-주입dependency-injection을-구현하는-방법">NestJS에서 의존성 주입(Dependency Injection)을 구현하는 방법</h3>
<p>의존성 주입(Dependency Injection, DI)은 객체지향 프로그래밍에서 객체 간의 의존 관계를 외부에서 주입해주는 디자인 패턴이다. NestJS에서는 의존성 주입을 통해 컴포넌트 간의 의존성을 효율적으로 관리하며, 이로 인해 코드의 결합도가 낮아지고 유지보수와 테스트가 용이해진다.</p>
<h4 id="클래스-생성자란">클래스 생성자란?</h4>
<p>클래스 생성자는 클래스의 인스턴스가 생성될 때 호출되는 특수한 메서드이다. 생성자는 주로 객체를 초기화하는 데 사용되며, 클래스 내부의 상태를 설정하거나 외부에서 주입받은 의존성을 클래스 내부에서 사용할 수 있도록 해준다.</p>
<h4 id="nestjs에서-의존성-주입-구현하기">NestJS에서 의존성 주입 구현하기</h4>
<p>NestJS에서는 <span style="color:red">&quot;@Injectable&quot; 데코레이터</span>를 사용하여 의존성을 주입할 클래스를 표시한다. 이 데코레이터는 NestJS에게 해당 클래스가 의존성 주입이 가능하다는 것을 알려준다.</p>
<p>의존성을 주입받으려는 클래스의 생성자에는 주입받을 서비스나 컴포넌트를 파라미터로 설정하면 된다. 
그러면 NestJS는 이 생성자를 호출할 때 필요한 의존성을 자동으로 주입해준다. </p>
<h4 id="직접-인스턴스를-생성하는-경우">직접 인스턴스를 생성하는 경우</h4>
<p>UserService, UserRepository가 있을 때 의존성을 주입하지 않고 직접 생성했다면, 
예제 코드는 아래와 같을 것이다.</p>
<p><img src="https://velog.velcdn.com/images/i-can-do/post/225d4465-71c1-4cb3-a1b3-cfcf3ac0ddd3/image.png" alt="">
이 방식에는 문제점이 있다.</p>
<ol>
<li>의존성 관리의 어려움: 만약 UserRepository가 다른 서비스나 외부 모듈에 의존하고 있다면, UserService도 해당 의존성을 직접 생성해야한다. 이렇게 의존성이 변경되면 UserService의 생성코드도 함께 수정해야한다.</li>
<li>테스트의 어려움: UserRepository를 Mock 객체도 대체하기 어렵다.</br>

</li>
</ol>
<h4 id="의존성-주입을-통한-해결">의존성 주입을 통한 해결</h4>
<p>반면에 의존성을 주입하여 객체의 생성과 관리 책임을 NestJS 프레임워크에게 맡겼다면, </p>
<p><img src="https://velog.velcdn.com/images/i-can-do/post/2482ca68-e5f7-463f-ba61-d64e0c0f8114/image.png" alt=""></p>
<ol>
<li>의존성 관리의 용이함: UserService는 UserRepository의 구체적인 구현에 의존하지 않는다. 의존성 관리와 객체 생성은 NestJS가 자동으로 처리해준다.</li>
<li>유연한 코드 유지 보수: UserRepository의 구현이 변경되더라도 UserService의 코드는 수정할 필요가 없다.</li>
<li>테스트 용이성: 테스트 환경에서 Mock 객체를 사용하여 의존성을 대체할 수 있다.</li>
</ol>
<p>애플리케이션이 시작될 때, NestJS는 모든 &quot;@Injectable&quot; 데코레이터가 붙은 클래스를 스캔하고, 각 클래스의 의존성을 분석하여 필요한 인스턴스를 자동으로 생성하고 관리해준다. 이렇게 함으로써 서비스 클래스는 의존성을 직접 생성하지 않고, NestJS가 이 모든 과정을 관리해준다. 결과적으로, 의존성 주입을 사용하면 코드의 결합도가 낮아지고, 유지보수와 테스트가 용이해진다.</p>
</br>

<h4 id="제어의-역전inversion-of-control-ioc">제어의 역전(Inversion of Control, IoC)</h4>
<p>제어의 역전은 애플리케이션의 흐름과 제어를 객체가 아닌 외부 프레임워크가 관리하도록 하는 디자인 패턴이다. 의존성 주입은 제어의 역전을 구현하는 대표적인 방법이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 2024 노랭이 개정판 :: 제2과목 제1장 SQL 기본2]]></title>
            <link>https://velog.io/@i-can-do/SQLD-2024-%EB%85%B8%EB%9E%AD%EC%9D%B4-%EA%B0%9C%EC%A0%95%ED%8C%90-%EC%A0%9C2%EA%B3%BC%EB%AA%A9-%EC%A0%9C1%EC%9E%A5-SQL-%EA%B8%B0%EB%B3%B82</link>
            <guid>https://velog.io/@i-can-do/SQLD-2024-%EB%85%B8%EB%9E%AD%EC%9D%B4-%EA%B0%9C%EC%A0%95%ED%8C%90-%EC%A0%9C2%EA%B3%BC%EB%AA%A9-%EC%A0%9C1%EC%9E%A5-SQL-%EA%B8%B0%EB%B3%B82</guid>
            <pubDate>Mon, 05 Aug 2024 01:33:54 GMT</pubDate>
            <description><![CDATA[<h4 id="26-아래-sql을-순서대로-실행했을-때-최종적으로-반영되는-sql을-모두-고른-것은">26. 아래 SQL을 순서대로 실행했을 때 최종적으로 반영되는 SQL을 모두 고른 것은?</h4>
<p>(가) INSERT INTO emp (empno, ename, deptno) VALUES (999, &#39;Smith&#39;, 10);
SAVEPOINT a;
(나) DELETE emp WHERE empno = 202;
SAVEPOINT b;
(다) UPDATE emp SET ename = &#39;Clark&#39;
ROLLBACK TO SAVEPOINT a;
(라) INSERT INTO emp (empno, ename, deptno) VALUES (300, &#39;Thomas&#39;, 30);
SAVEPOINT c;
(마) DELETE emp WHERE deptno = 20;
COMMIT;</p>
<p><span style="color: red">④ (가), (라), (마)</span>
<span style="color: green"> -&gt; (다)에서 SAVEPOINT A 이후의 모든 트랜잭션을 롤백했기 때문에, (나), (다) 트랜잭션은 모두 취소된다. </span></p>
</br>

<h4 id="27-아래-sql의-실행-결과로-가장-적절한-것은">27. 아래 SQL의 실행 결과로 가장 적절한 것은?</h4>
<p>[TABLE_A]</p>
<table>
<thead>
<tr>
<th>TABKEY</th>
<th>COLA</th>
<th>COLB</th>
<th>COLC</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>NULL</td>
<td>가</td>
<td>NULL</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>가</td>
<td>5</td>
</tr>
<tr>
<td>3</td>
<td>NULL</td>
<td>나</td>
<td>2</td>
</tr>
<tr>
<td>4</td>
<td>3</td>
<td>나</td>
<td>0</td>
</tr>
<tr>
<td>5</td>
<td>NULL</td>
<td>NULL</td>
<td>3</td>
</tr>
<tr>
<td>6</td>
<td>5</td>
<td>다</td>
<td>0</td>
</tr>
<tr>
<td>7</td>
<td>NULL</td>
<td>다</td>
<td>NULL</td>
</tr>
</tbody></table>
<p>[SQL]</p>
<pre><code>SELECT COLB
    , MAX(COLA) AS COLA1    
    , MIN(COLA) AS COLA2
    , SUM(COLA + COLC) AS SUMAC
FROM TABLE_A
GROUP BY COLB;</code></pre><span style="color: red">
  ①

<table>
<thead>
<tr>
<th>TABKEY</th>
<th>COLA</th>
<th>COLB</th>
<th>COLC</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>NULL</td>
<td>가</td>
<td>NULL</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>가</td>
<td>5</td>
</tr>
<tr>
<td>3</td>
<td>NULL</td>
<td>나</td>
<td>2</td>
</tr>
<tr>
<td>4</td>
<td>3</td>
<td>나</td>
<td>0</td>
</tr>
<tr>
<td></span></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<p><span style="color: green"> -&gt; GROUP BY 절은 NULL 데이터도 집계에 포함하기 때문에 colb 컬럼에 있는 NULL 행도 결과로 출력된다.
MIN, MAX 함수는 NULL 칼럼의 값이 NULL이 아닌 행 중에서의 최소, 최댓값을 추출한다.
NULL과의 사칙연산(+, -, *, /)은 결과가 NULL이므로 cola 또는 colb 둘 중 하나 칼럼의 값이 NULL이라면 NULL을 반환한다. </span>
</br></p>
<h4 id="28-아래-sql의-실행-결과로-가장-적절한-것은">28. 아래 SQL의 실행 결과로 가장 적절한 것은?</h4>
<p>[TBL]</p>
<table>
<thead>
<tr>
<th>ID</th>
</tr>
</thead>
<tbody><tr>
<td>100</td>
</tr>
<tr>
<td>100</td>
</tr>
<tr>
<td>200</td>
</tr>
<tr>
<td>200</td>
</tr>
<tr>
<td>200</td>
</tr>
<tr>
<td>999</td>
</tr>
<tr>
<td>999</td>
</tr>
</tbody></table>
<pre><code>SELECT ID FROM TBL
GROUP BY ID
HAVING COUNT(*) = 2
ORDER BY (CASE WHEN IN = 999 THEN 0 ELSE ID END)</code></pre><span style="color: red">
  ②

<table>
<thead>
<tr>
<th>ID</th>
</tr>
</thead>
<tbody><tr>
<td>999</td>
</tr>
<tr>
<td>100</td>
</tr>
</tbody></table>
</span>
<span style="color: green"> -> ORDER BY의 기본 정렬 순서는 오름차순(ASC)이다. 오라클에서는 NULL값을 가장 큰 값으로 간주, SQL Server에서는 가장 작은 값으로 간주하기 때문에 정렬 순서에 신경써야한다.</span>
</br>

<h4 id="29-오류가-발생하는-sql은">29. 오류가 발생하는 SQL은?</h4>
<p>① SELECT 지역, SUM(매출금액) AS 매출금액
FROM 지역별매출
GROUP BY 지역
ORDER BY 매출금액 DESC;
② SELECT 지역, 매출금액
FROM 지역별매출
ORDER BY 년 ASC;
<span style="color: green"> -&gt; SQL 실행 순서에 의하면 SELECT절 이후에 ORDER BY 절이 수행되기 때문에 SELECT 절에 기술되지 않는 &#39;년&#39; 칼럼으로 정렬하는 것은 논리적으로 맞지 않다. 하지만 오라클은 행기반 DATABASE이므로 데이터를 엑세스할 때 행 전체 칼럼을 메모리에 로드한다. 이와 같은 특성으로 인해 SELECT 절에 기술되지 않은 칼럼으로 정렬을 할 수 있다. 단 아래와 같은 SQL일 경우에는 정렬을 할 수 없다.
SELECT 지역, 매출금액 FROM ( select 지역, 매출금액 from 지역별매출) ORDER BY 년 ASC;</span>
<span style="color: red">③ SELECT 지역, SUM(매출금액) AS 매출금액
FROM 지역별매출
GROUP BY 지역
ORDER BY 년 DESC;</span>
<span style="color: green"> -&gt; GROUP BY를 사용할 경우 GROUP BY 표현식이 아닌 값은 기술될 수 없다.</span>
④ SELECT 지역, SUM(매출금액) AS 매출금액
FROM 지역별매출
GROUP BY 지역
HAVING SUM(매출금액) &gt; 1000
ORDER BY COUNT(*) ASC;
<span style="color: green"> -&gt; GROUP BY 표현식이기에 가능하다.</span>
</br></p>
<h4 id="30-아래-sql의-실행-결과로-가장-적절한-것은">30. 아래 SQL의 실행 결과로 가장 적절한 것은?</h4>
<p>SELECT TO_CHAR(TO_DATE(&#39;2019.02.25&#39;, &#39;YYYY.MM.DD&#39;) + 1/12/(60/30), &#39;YYYY.MM.DD HH24:MI:SS) FROM DUAL;</p>
<p><span style="color: red">③ 2019.02.25 01:00:00 </span>
<span style="color: green"> -&gt;1/12/(60/30) 은, 하루(24시간)을 12시간으로 나누면 2시간이고, (60/30)은 2니까 2시간을 2로 나누면 1시간이다. 2019.02.25 00시 00분 00초에 1시간을 더하면 3번이 된다. </span>
</br></p>
<h4 id="31-실행-결과가-null인-sq은-단-dbms는-오라클로-가정">31. 실행 결과가 NULL인 SQ은? (단, DBMS는 오라클로 가정)</h4>
<p>① SELECT COALESCE(NULL, &#39;A&#39;) FROM DUAL;
<span style="color: green"> -&gt; COALESCE 함수는 주어진 인수 목록에서 NULL이 아닌 첫 번째 값을 반환한다.</span>
<span style="color: red">② SELECT NULLIF(&#39;A&#39;, &#39;A&#39;) FROM DUAL; </span>
<span style="color: green"> -&gt; NULLIF(표현식1, 표현식2) 함수는 표현식1과 표현식2가 같으면 NULL, 아니면 표현식1을 리턴한다.</span>
③ SELECT NVL(&#39;A&#39;, NULL) FROM DUAL;
<span style="color: green"> -&gt; NVL 함수는 주어진 첫 번째 인수가 NULL인 경우 두 번째 인수를 반환하고, 첫 번째 인수가 NULL이 아닌 경우에는 그대로 첫 번째 인수를 반환하는 오라클의 함수다. 따라서 A를 반환한다.</span>
④ SELECT NVL(NULL, 0) + 10 FROM DUAL;
<span style="color: green"> -&gt; 두 번째 인수 0을 반환하고 + 10을 하기 때문에 정답이 아니다. </span>
</br></p>
<h4 id="32-select-문장의-실행-순서를-올바르게-나열한-것은">32. SELECT 문장의 실행 순서를 올바르게 나열한 것은?</h4>
<p><span style="color: red">④ FROM-WHERE-GROUP BY-HAVING-SELECT-ORDER BY</span>
</br></p>
<h4 id="35-아래에서-join에-대한-설명을-가장-적절한-것은">35. 아래에서 JOIN에 대한 설명을 가장 적절한 것은?</h4>
<p>(가) 일반적으로 조인은 PK와 FK값의 연관성에 의해 성립된다.
(나) DBMS 옵티마이저는 FROM 절에 나열된 테이블들을 임의로 3개 정도씩 묶어서 조인을 처리한다.
(다) EQUI JOIN은 조인에 관여하는 테이블 간의 칼럼 값들이 정확하게 일치하는 경우에 사용되는 방법이다.
(라) EQUI JOIN은 &#39;=&#39; 연산자에 의해서만 수행되며, 그 이외의 비교 연산자를 사용하는 경우에는 모두 NON EQUI JOIN이다.
(마) 대부분 NON EQUI JOIN을 수행할 수 있지만, 때로는 설계상의 이유로 수행이 불가능한 경우도 있다.
<span style="color: red">④ (가), (다), (라), (마) </span>
<span style="color: green"> -&gt; DBMS 옵티마이저는 FROM 절에 나열된 테이블이 아무리 많아도 항상 2개의 테이블씩 짝을 지어 JOIN을 수행한다. </span>
</br></p>
<h4 id="37-순수-관계-연산자로-가장-적절하지-않은-것은">37. 순수 관계 연산자로 가장 적절하지 않은 것은?</h4>
<p>① SELECT
<span style="color: red">② UPDATE</span>
③ JOIN
④ DIVIDE
<span style="color: green">-&gt; 순수 관계 연산자에는 SELECT, PROJECT, JOIN, DIVIDE가 있다.</span>
</br></p>
<h4 id="39">39.</h4>
<img src="https://velog.velcdn.com/images/i-can-do/post/081b81d8-3fa5-4ca2-b2b1-3801e03e5f0c/image.jpg" style="width: 70%; height: 60%;">

<p><span style="color: green"> -&gt; 
  ① 생산제품 엔터티는 WHERE절에 최소 2번 나타나야 한다.
③ 데이터 모델을 보면 제품과 생산라인 엔터티에는 생산제품과 대응되지 않는 레코드가 있을 수 있다.
④ 특정 생산라인에서 생산되는 제품의 제품며을 알기 위해서는 제품과 생산제품까지 2개의 엔터티만을 inner join하면 된다. </span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 2024 노랭이 개정판 :: 제2과목 제1장 SQL 기본]]></title>
            <link>https://velog.io/@i-can-do/SQLD-2024-%EB%85%B8%EB%9E%AD%EC%9D%B4-%EA%B0%9C%EC%A0%95%ED%8C%90-%EC%A0%9C2%EA%B3%BC%EB%AA%A9-%EC%A0%9C1%EC%9E%A5-SQL-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@i-can-do/SQLD-2024-%EB%85%B8%EB%9E%AD%EC%9D%B4-%EA%B0%9C%EC%A0%95%ED%8C%90-%EC%A0%9C2%EA%B3%BC%EB%AA%A9-%EC%A0%9C1%EC%9E%A5-SQL-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Fri, 02 Aug 2024 06:22:51 GMT</pubDate>
            <description><![CDATA[<ol>
<li>DML(데이터 조작어: Data Manipulation Language)
: 데이터를 조회, 검색, 변형을 가하는 종류의 명령어
: SELECT, INSERT, UPDATE, DELETE</li>
<li>DDL(데이터 정의어: Data Definition Language)
: 테이블과 같은 데이터 구조를 정의하는 데 사용되는 명령어들로 그러한 구조를 생성, 변경, 삭제, 이름을 바꾸는 데이터 구조와 관련된 명령어
: CREATE, ALTER, DROP, RENAME</li>
<li>DCL(데이터 제어어: Data Control Language)
: 데이터베이스에 접근하고 객체들을 사용하도록 권한을 주고 회수하는 명령어
: GRANT, REVOKE</li>
<li>TCL(트랜잭션 제어어: Transaction Control Language)
: 논리적인 작업의 단위를 묶어서 DML에 의해 조작된 결과를 작업단위 별로 제어하는 명령어
: COMMIT, ROLLBACK</li>
</ol>
<h4 id="3-아래-내용에-해당하는-sql-명령어의-종류는">3. 아래 내용에 해당하는 SQL 명령어의 종류는?</h4>
<p>논리적인 작업의 단위를 묶어 DML에 의해 조작된 결과를 작업단위별로 제어하는 명령어인 Commit, Rollback, Savepoint등이 여기에 해당하며, 일부에서는 DCL(Data Control Language)로 분류하기도 한다.</p>
<p>① DDL
② DML
<span style="color: red">③ TCL</span>
<span style="color: green"> -&gt; 트랜잭션을 제어하는 명령어</span>
④ TML
</br></p>
<h4 id="4-select-문에-대한-설명으로-가장-적절하지-않은-것은">4. SELECT 문에 대한 설명으로 가장 적절하지 않은 것은?</h4>
<p>① WHERE 절은 필수가 아니므로 생략 가능하다.
② DISTINCT 옵션을 통해 중복된 데이터가 있을 경우 1건으로 처리해 출력할 수 있다.
<span style="color: red">③ FROM 절이 없는 다음 문장 &quot;SELECT COL1, COL2&quot;은 에러 없이 수행된다.</span>
<span style="color:green"> -&gt; SELECT, FROM은 필수이므로 생략되면 에러가 발생된다. </span>
④ SELECT list에 서브쿼리가 사용될 수 있다.
</br></p>
<h4 id="5-sql의-종류와-해당되는-명령어를-바르게-연결한-것은">5. SQL의 종류와 해당되는 명령어를 바르게 연결한 것은?</h4>
<p><span style="color:red">① DML - SELECT</span>
② TCL - GRANT
  <span style="color:green"> -&gt; GRANT는 DCL </span>
③ DCL - DROP
<span style="color:green"> -&gt; DROP은 DDL </span>
④ DML - ALTER
<span style="color:green"> -&gt; ALTER은 DDL </span>
</br></p>
<h4 id="9-아래-sql의-수행-결과로-가장-적절한-것은">9. 아래 SQL의 수행 결과로 가장 적절한 것은?</h4>
<p>[SQL]
SELECT SUM(COL2) + SUM(COL3) FROM TAB_A;
SELECT SUM(COL2) + SUM(COL3) FROM TAB_A WHERE COL1 &gt; 0;
SELECT SUM(COL2) + SUM(COL3) FROM TAB_A WHERE COL1 IS NOT NULL;
SELECT SUM(COL2) + SUM(COL3) FROM TAB_A WHERE COL1 IS NULL;</p>
<p>[TAB_A]</p>
<table>
<thead>
<tr>
<th>COL1</th>
<th>COL2</th>
<th>COL3</th>
</tr>
</thead>
<tbody><tr>
<td>30</td>
<td>NULL</td>
<td>20</td>
</tr>
<tr>
<td>NULL</td>
<td>50</td>
<td>10</td>
</tr>
<tr>
<td>0</td>
<td>10</td>
<td>NULL</td>
</tr>
</tbody></table>
<p><span style="color:green">1. SUM(집계함수)은 NULL을 무시한다. 60 + 30 = 90
2. COL1 &gt; 0인 행은 첫번째 행 뿐이다(NULL값과의 비교연산은 FALSE를 리턴함) 
NULL + 20 = NULL(NULL과의 연산 결과는 NULL을 리턴한다)
3. COL1 IS NOT NULL인 첫번째과 세번째 행의 SUM을 구한다. 10 + 20 = 30
4. COL1 IS NULL인 두번째 행의 SUM을 구한다. 50 + 10 = 60</span>
<span style="color:red">③ 90, NULL, 30, 60</span>
</br></p>
<h4 id="11-아래에-대한-설명으로-가장-적절한-것은">11. 아래에 대한 설명으로 가장 적절한 것은?</h4>
<pre><code>CREATE TABLE 서비스
(
       서비스번호 VARCHAR2(10) PRIMARY KEY,
    서비스명 VARCHAR2(100) NULL,
    개시일자 DATE NOT NULL
);

[SQL]
㉠ SELECT * FROM 서비스 WHERE 서비스번호 = 1;
㉡ INSERT INTO 서비스 VALUES (&#39;999&#39;, &#39;&#39;, &#39;2015-11-11&#39;);
㉢ SELECT * FROM 서비스 WHERE 서비스명 = &#39;&#39;;
㉣ SELECT * FROM 서비스 WHERE 서비스명 IS NULL;
</code></pre><p>① 서비스번호 칼럼의 레코드 중 하나의 레코드라도 &#39;001&#39;과 같은 숫자 형식으로 입력되어 있다면 ㉠은 오류 없이 실행된다.
<span style="color:green">-&gt; 서비스번호 칼럼의 모든 레코드가 001과 같은 숫자 형식으로 입력되어 있어야 오류가 발생하지 않는다.</span></p>
<p>② 오라클에서 ㉡과 같이 데이터를 입력하였을 때, 서비스명 칼럼에 공백 문자 데이터가 입력된다.
<span style="color:green">-&gt; ㉡과 같이 데이터를 입력하면 서비스명 칼럼의 데이터에 대해서 오라클에서는 NULL로 입력된다.</span></p>
<p>③ 오라클에서 ㉡과 같이 데이터를 입력하고 ㉢과 같이 조회하였을 때, 데이터는 조회된다.
<span style="color:green"> -&gt; ㉡과 같이 데이터가 입력되어있을 때 오라클에서 데이터를 조회하려면 서비스명 IS NULL 조건으로 조회하여야한다. </span></p>
<p><span style="color:red">④ SQL Server에서 ㉡과 같이 데이터를 입력하고 ㉣과 같이 조회하였을 때, 데이터는 조회되지 않는다.</span>
<span style="color:green"> -&gt; ㉡과 같이 데이터가 입력되어있을 때 SQL Server에서 데이터를 조회하려면 서비스명 = &#39;&#39; 조건으로 조회하여야한다. </span>
</br></p>
<h4 id="12-함수의-실행-결과로-가장-적절하지-않은-것은단-a의-아스키코드는-65이다">12. 함수의 실행 결과로 가장 적절하지 않은 것은?(단, A의 아스키코드는 65이다.)</h4>
<p>① LOWER(&#39;SQL Expert&#39;) : &#39;sql expert&#39;
② UPPER(&#39;SQL Expert&#39;) : &#39;SQL EXPERT&#39;
③ ASCII(&#39;A) : 65
<span style="color:red">④ LTRIM(&#39;xxYYZZxYZxx&#39;, &#39;x&#39;) : &#39;YYZZxYZ&#39;</span>
<span style="color:green"> -&gt; LTRIM은 첫 번째 인자 값인 문자열의 왼쪽 첫 문자부터 확인해서 두 번째 인자 값인 지정문자가 나타나면 해당 문자를 제거한다. 다른 문자 사이 또는 오른쪽에 있는 지정 문자는 제거되지 않는다. 따라서, LTRIM(&#39;xxYYZZxYZxx&#39;, &#39;x&#39;)의 결과는 &#39;YYZZxYZxx&#39; 이다.</span></p>
<p><span style="color:green"> -&gt; 추가: SUBSTR/SUBSTRING(문자열, m[, n]): 문자열 중 m위치에서 n개의 문자 길이에 해당하는 문자를 돌려준다. n이 생략되면 마지막 문자까지이다. </span>
</br></p>
<h4 id="15-아래를-참고할-때-sql의-실행-결과로-가장-적절한-것은-단-이해를-돕기-위해-⬇️는-줄바꿈을-의미하며-실제-저장값이-아님-또한-chr10의-ascii-값은-줄바꿈을-의미">15. 아래를 참고할 때 SQL의 실행 결과로 가장 적절한 것은? (단, 이해를 돕기 위해 ⬇️는 줄바꿈을 의미하며 실제 저장값이 아님, 또한 CHR(10)의 ASCII 값은 줄바꿈을 의미)</h4>
<p>[TAB1]</p>
<table>
<thead>
<tr>
<th>ROWNUM</th>
<th>C1</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>A</td>
</tr>
<tr>
<td></td>
<td>↓</td>
</tr>
<tr>
<td></td>
<td>A</td>
</tr>
<tr>
<td>2</td>
<td>B</td>
</tr>
<tr>
<td></td>
<td>↓</td>
</tr>
<tr>
<td></td>
<td>B</td>
</tr>
<tr>
<td></td>
<td>↓</td>
</tr>
<tr>
<td></td>
<td>B</td>
</tr>
</tbody></table>
<p>SELECT SUM(CC) 
FROM
(
SELECT(LENGTH(C1) - LENGTH(REPLACE(C1, CHR(10))) + 1) CC FROM TAB1
);</p>
<span style="color:green">
  LENGTH(C1) - LENGTH(REPLACE(C1, CHR(10))) + 1 : 3 - 2 + 1  = 2</span></br>
<span style="color:green">  
  LENGTH(C1) - LENGTH(REPLACE(C1, CHR(10))) + 1 : 5 - 3 + 1 = 3
</span>
</br>

<p><span style="color:red">③ 5</span>
</br></p>
<h4 id="16-아래-sql의-실행-결과로-가장-적절한-것은단-dbms는-오라클로-가정">16. 아래 SQL의 실행 결과로 가장 적절한 것은(단, DBMS는 오라클로 가정)</h4>
<p>SELECT TO_CHAR(TO_DATE(&#39;2023.01.10 10&#39;, &#39;YYYY.MM.DD HH24&#39;) + 1/24/(60/10), &#39;YYYY.MM.DD HH24:MI:SS&#39;) FROM DUAL;
<span style="color:red">③ 2023.01.10 10:10:00</span>
<span style="color:green"> -&gt; 오라클에서 날짜의 연산은 숫자의 연산과 같다. 1/24/60 = 1분을 의미한다. 1/24는 1시간을 의미한다. 1시간을 (60/10) 6으로 나누면 60분/6 = 10분이 된다. 2023년 1월 10일 10시에 10분을 더한 3번이 답이 된다.</span>
</br></p>
<h4 id="19-아래-sql에-대한-설명으로-가장-적절한-것은-단-고객이름은-중복되지-않는다고-가정">19. 아래 SQL에 대한 설명으로 가장 적절한 것은? (단, 고객이름은 중복되지 않는다고 가정)</h4>
<p>고객 (고객번호, 고객이름, 주소, 전화번호)
상품 (상품번호, 상품이름, 무게, 가격)
주문 (고객번호, 상품번호, 수량, 날짜)</p>
<p>[SQL]
SELECT 고객이름, SUM(수량)
FROM 고객, 상품, 주문
WHERE 고객.고객번호 = 주문.고객번호
AND 상품.상품번호 = 주문.상품번호
GROUP BY 고객.고객이름
HAVING MAX(수량) &gt; 10;</p>
<p>① 고객번호가 10보다 큰 고객이름과 주문한 수량의 합을 구한다.
<span style="color:red">② 수량이 10보다 큰 주문을 한 고객이름과 주문한 수량의 합을 구한다.</span>
③ 열한 번 이상 상품을 주문한 고객이름과 주문한 수량의 합을 구한다.
④ 주문한 수량의 합이 10보다 큰 고객이름과 주문한 수량의 합을 구한다.
</br></p>
<h4 id="20-emp-테이블에서-mrg의-값이-7698과-같으면-null을-표시하고-같지-않으면-mgr을-표시하려고-할-때-빈칸-㉠에-들어갈-함수는">20. EMP 테이블에서 MRG의 값이 7698과 같으면 NULL을 표시하고, 같지 않으면 MGR을 표시하려고 할 때 빈칸 ㉠에 들어갈 함수는?</h4>
<p>SELECT ENAME, EMPNO, MGR, ㉠ (MGR, 7698) AS NM FROM EMP;</p>
<p><span style="color:red">① NULLIF</span>
<span style="color:green"> -&gt; NULLIF(x,y) : x이 y와 같으면 NULL을, 같지 않으면 x를 리턴한다. </span>
② NVL
<span style="color:green"> -&gt; NVL(x,y) / ISNULL(x,y) : x의 결괏값이 NULL이면 y의 값을 출력한다.</span>
③ IFNULL
④ COALESCE
<span style="color:green"> -&gt; COALESCE(표현식1, 표현식2, ...) : 임의의 개수 표현식에서 NULL이 아닌 최초의 표현식을 나타낸다. 모든 표현식이 NULL이라면 NULL을 리턴한다. </span>
</br></p>
<h4 id="21-실행-결과가-다른-하나는">21. 실행 결과가 다른 하나는?</h4>
<p>① SELECT DNAME, LOC, DEPTNO 
FROM DEPT
ORDER BY DNAME, LOC, 3 DESC;
<span style="color:green">-&gt; 첫 번째 열, 두 번째 열은 오름차순 정렬, 3 DESC는 세 번째 열인 DEPTNO를 내림차순으로 정렬한다는 뜻. </span></p>
<p>② SELECT DNAME, LOC, DEPTNO
  FROM DEPT
  ORDER BY DNAME, AREA, DEPTNO DESC;
  <span style="color:green">-&gt; 첫 번째 열, 두 번째 열은 오름차순 정렬, 세 번째 열은 내림차순으로 정렬</span></p>
<p>③ SELECT DNAME, LOC AREA, DEPTNO
FROM DEPT
ORDER BY 1, AREA, 3DESC;
<span style="color:green">-&gt; 첫 번째 열, 두 번째 열은 오름차순 정렬, 3 DESC는 세 번째 열인 DEPTNO를 내림차순으로 정렬한다는 뜻. </span></p>
<p><span style="color:red">④ SELECT DNAME DEPT, LOC AREA, DEPTNO
FROM DEPT
ORDER BY DEPT DESC, LOC, 3 DESC;</span>
<span style="color:green">-&gt; 첫 번째 열과 세 번째 열을 내림차순으로 정렬하기 때문에 나머지와 결과가 다르다. </span>
</br></p>
<h4 id="22-아래는-이름이-4문자-이상이고-2번째-문자가-s인-학번을-출력하는-sql이다-빈칸-㉠에-들어갈-수-있는-내용으로-가장-적절하지-않은-것은">22. 아래는 이름이 4문자 이상이고 2번째 문자가 S인 학번을 출력하는 SQL이다. 빈칸 ㉠에 들어갈 수 있는 내용으로 가장 적절하지 않은 것은?</h4>
<p>SELECT 학번
FROM 학생
WHERE 학생, 이름 LIKE ㉠</p>
<p><span style="color:red">① &#39;%S_ _ <em>&#39; </span>
<span style="color:green"> -&gt; %위치에 아무런 문자가 들어가지 않을 수도 있다. 따라서 S가 첫 문자가 될 수도 있으므로 옳지 않다.</span>
② &#39;<em>S% _</em>&#39;
③ &#39;_S _ % _ _&#39;
④ &#39;_S</em> _%&#39;</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 2024 노랭이 개정판 :: 데이터 모델과 SQL 오답노트]]></title>
            <link>https://velog.io/@i-can-do/SQLD-2024-%EB%85%B8%EB%9E%AD%EC%9D%B4-%EA%B0%9C%EC%A0%95%ED%8C%90-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-SQL-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@i-can-do/SQLD-2024-%EB%85%B8%EB%9E%AD%EC%9D%B4-%EA%B0%9C%EC%A0%95%ED%8C%90-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-SQL-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Wed, 31 Jul 2024 06:49:32 GMT</pubDate>
            <description><![CDATA[<h4 id="34-속성abcde로-구성된-릴레이션에서-아래와-같은-함수-종속성이-존재할-때-이-릴레이션의-후보-키로-가장-적절하지-않은-것은">34. 속성(a,b,c,d,e)로 구성된 릴레이션에서 아래와 같은 함수 종속성이 존재할 때, 이 릴레이션의 후보 키로 가장 적절하지 않은 것은?</h4>
<p>ab -&gt; cde, e -&gt; b, d -&gt; ab
① d
② ab
③ ac
④ ae
</br></p>
<h4 id="36-아래-엔터티에-필요한-정규화와-분리된-스키마-구조로-가장-적절한-것은">36. 아래 엔터티에 필요한 정규화와 분리된 스키마 구조로 가장 적절한 것은?</h4>
<p>[보관금원장]
관서번호
납부자번호
.............................
관리점번호
관서명
상태
관서등록일자
직급명
통신번호</p>
<p>함수종속성(FD) :
{관서번호, 납부자번호} -&gt; {직급명, 통신번호}
{관서번호} -&gt; {관리점번호, 관서명, 상태, 관서등록일자}</p>
<p><span style="color:red">③ 2차 정규화 - 정규화테이블{관서번호, 관리점번호, 관서명, 상태, 관서등록일자}</span>
<span style="color:green">-&gt; 관리점 번호는 관서 번호와 연관성이 없으니 별도 엔터티로 분류해도 된다.</span>
</br></p>
<h4 id="38-아래와-같이-전제조건이-있을-때-테이블에서-나타날-수-있는-현상으로-가장-적절한-것은">38. 아래와 같이 전제조건이 있을 때 테이블에서 나타날 수 있는 현상으로 가장 적절한 것은?</h4>
<p><img src="https://velog.velcdn.com/images/i-can-do/post/542e05eb-5afd-4a8f-9914-d68a26010282/image.jpg
" width="50%" height="n%">
① 조회 조건이 유형기능분류코드에 따라 반복되는 그룹이 칼럼단위로 되어 있으므로 제1정규형이라고 할 수 있다.
<span style="color:green">-&gt; 칼럼에 의한 반복적인 속성값을 갖는 형태는 속성의 원자성을 위배한 1차 정규화의 대상이 된다. </span>
② 유형기능분류코드에 대해 where절에 조건으로 들어오는 값이 있으므로 PK와 이에 대한 인덱스만 있으면 SQL문장은 빠르게 수행될 수 있다고 할 수 있다.
<span style="color:green">-&gt; 반복적인 속성 나열 형태에서는 각 속성에 대해 &#39;or&#39; 연산자로 연결된 조건들이 사용된다. 어느 하나의 속성이라도 인덱스가 설정되어 있지 않으면 모든 조건절들이 전체 데이터 스캔으로 처리되기 때문에 성능 저하가 나타날 수 있다. </span>
③ 유형기능분류코드가 일반속성 안에서 반복적으로 속성이 구분되어 있기 때문에 이전종속을 수행해야 하는 제2정규형이라 할 수 있다.
<span style="color:red">④ 조회 성능을 위해 유형기능분류코드 각각에 대하여 개별로 인덱스를 모두 생성할 경우 입력, 수정, 삭제 때 성능이 저하되므로 제1차 정규화를 수행한 후 인덱스를 적용하는 것이 좋다. </span>
</br></p>
<h4 id="39-아래-논리-데이터-모델을-3차-정규화까지-수행했을-때-도출되는-엔터티-수로-가장-적절한-것은">39. 아래 논리 데이터 모델을 3차 정규화까지 수행했을 때 도출되는 엔터티 수로 가장 적절한 것은?</h4>
<img src="https://velog.velcdn.com/images/i-can-do/post/68703ab5-69c4-4172-b14b-fe9a308f6192/image.jpg" width="50%" height="n%">

<p><span style="color:red">③ 7</span>
<span style="color:green">-&gt; 학과, 학생, 교수, LAB실 이용신청, (도서)대출, 대출도서, 도서 총 7개 </span>
</br></p>
<h4 id="40-아래에서-빈칸-㉠-㉡에-들어갈-용어로-가장-적절한-것은">40. 아래에서 빈칸 ㉠, ㉡에 들어갈 용어로 가장 적절한 것은?</h4>
<p>어떤 릴레이션 R이 ㉠이고, 기본키에 속하지 않은 속성 모두가 기본키에 이행적 함수종속이 아닐 때 ㉡에 속한다.
<span style="color:red">③ ㉠ 제2정규형, ㉡ 제3정규형 </span>
</br></p>
<h4 id="41-데이터-모델링의-정규화에-대한-설명으로-가장-적절하지-않은-것은">41. 데이터 모델링의 정규화에 대한 설명으로 가장 적절하지 않은 것은?</h4>
<p><span style="color:red">① 정규화는 개념 데이터 모델의 일관성을 확보하고 중복을 제거하여 속성들이 가장 적절한 엔터티에 배치되도록 한다.</span>
<span style="color:green">-&gt; 정규화는 논리 데이터 모델 상세화 과정의 대표적인 활동으로, 논리 데이터 모델의 일관성을 확보하고 중복을 제거하여 속성들이 가장 적절한 엔터티에 배치되도록 함으로써 보다 더 신뢰성 있는 데이터구조를 얻는 데 목적이 있다.</span>
② 제1정규형은 모든 인스턴스가 반드시 하나의 값을 가져야 함을 의미한다.
③ 제3정규형을 만족하는 엔터티의 일반속성은 주식별자 전체에 종속적이다.
④ 반정규화는 성능을 위해 데이터 중복을 허용하는 것이지만 성능의 향상을 항상 보장하는 것은 아니다.</br></p>
<h4 id="42-관계와-조인에-대한-설명으로-가장-적절하지-않은-것은">42. 관계와 조인에 대한 설명으로 가장 적절하지 않은 것은?</h4>
<p>① 조인이란 식별자를 상속하고, 상속된 속성을 매핑키로 활용하여 데이터를 결합하는 것을 의미한다.
<span style="color:red">② 부모의 식별자를 자식의 일반속성으로 상속하면 식별 관계, 부모의 식별자를 자신의 식별자에 포함하면 비식별 관계라고 할 수 있다.</span>
<span style="color:green"> -&gt; 부모의 식별자를 자식의 식별자에 포함하면 식별관계, 부모의 식별자를 자식의 일반속성으로 상속하면 비식별관계라고 할 수 있다.</span>
③ 관계를 맺는다는 것은 식별자를 상속시키고 해당 식별자를 매핑키로 활용해 데이터를 결합해 보겠다는 것을 의미한다.
④ &quot;SELECT B.고객명 FROM  주문 A, 고객 B WHERE A.고객번호 = B.고객번호&quot; 쿼리에서 조인키는 &quot;고객번호&quot;이다.
</br></p>
<h4 id="44-아래와-같이-수강지도-엔터티를-만들었을-때-이에-해당하는-정규형과-정규화의-대상으로-가장-적절한-것은">44. 아래와 같이 수강지도 엔터티를 만들었을 때 이에 해당하는 정규형과 정규화의 대상으로 가장 적절한 것은?</h4>
<p>[수강지도]
학번
과목코드
...................
성적
지도교수명
학과명</p>
<p>[함수종속성(FD)]</p>
<ol>
<li>학번 || 과목코드 -&gt; 성적</li>
<li>학번 -&gt; 지도교수명</li>
<li>학번 -&gt; 학과명</li>
</ol>
<p><span style="color:red"> ① 1차 정규형, 2차 정규화 대상 </span>
<span style="color:green"> -&gt; PK에 대해 반복이 되는 그룹이 존재하지 않으므로 1차 정규형이라고 할 수 있다.
부분함수종속의 규칙을 가지고 있으므로 2차 정규형이라고 할 수 없음.
2차 정규화의 대상이 되는 엔터티이다.</span>
</br></p>
<h4 id="49-null-값에-대한-설명으로-가장-적절한-것은">49. NULL 값에 대한 설명으로 가장 적절한 것은?</h4>
<h6 id="개발자로서-이걸-틀리다니">개발자로서 이걸 틀리다니...</h6>
<p><span style="color:red">① NULL 값에 어떤 숫자를 더해도 결과는 항상 NULL 이다.</span>
② NULL 값과 어떤 숫자의 크기를 비교해도 결과는 항상 NULL 이다.
<span style="color:green"> -&gt; NULL 값과 어떤 숫자의 크기를 비교한 결과는 항상 unknown이다.</span>
③ &quot;NULL = NULL&quot; 연산의 결과는 TRUE 이다.
<span style="color:green"> -&gt; &quot;NULL = NULL&quot; 연산의 결과는 FALSE 또는 unknown이다.</span>
④ 집계 함수를 계산할 때 NULL 값은 0으로 처리된다.
<span style="color:green"> -&gt; 집계 함수를 계산할 때 NULL 값은 0이 아니라 계산에서 제외된다.</span></p>
<blockquote>
<p>추가로 아래 사항을 기억하자.</p>
<p>컬럼이 총 14개이고 NULL인 컬럼이 4개 있을 때,
AVG(컬럼) = 10개 컬럼의 평균값
SUM(컬럼)/COUNT(*) = 14개 컬럼의 평균값</p>
<p>-&gt; 상황에 따라 집계 함수를 다르게 사용할 줄 알아야함</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 2024 노랭이 개정판 :: 데이터 모델링의 이해 오답노트]]></title>
            <link>https://velog.io/@i-can-do/SQLD-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B4-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@i-can-do/SQLD-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B4-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Mon, 29 Jul 2024 11:28:44 GMT</pubDate>
            <description><![CDATA[<h4 id="2-데이터-모델링에-대한-설명으로-가장-적절하지-않은-것은">2. 데이터 모델링에 대한 설명으로 가장 적절하지 않은 것은?</h4>
<p>① 업무 정보를 구성하는 기초가 되는 정보들을 일정한 표기법으로 표현한다.
② 분석된 모델로 데이터베이스를 생성하여 개발 및 데이터관리에 사용하기 위한 것이다.
<span style="color:red">③ 데이터베이스를 구축하는 목적으로 데이터 모델링을 수행하며 업무에 대한 설명은 별도의 표기법을 이용한다.</span>
<span style="color:green">-&gt; 데이터베이스만을 구축하기 위한 용도로 쓰이는 것이 아니다.</span>
④ 데이터 모델링 자체로서 업무의 흐름을 설명하고 분석하는 부분에 의미를 가지고 있다.</p>
</br>

<h4 id="5-데이터-독립성의-구성요소에-대한-설명으로-가장-적절하지-않은-것은">5. 데이터 독립성의 구성요소에 대한 설명으로 가장 적절하지 않은 것은?</h4>
<p>① 통합된 모든 사용자의 관점은 개념스키마와 관련이 있다.
② 물리적인 저장구조를 표현하는 스키마는 내부스키마이다.
<span style="color:red">③ view 단계는 여러 사용자 관점으로 구성하는 개념스키마에 해당한다.</span>
<span style="color:green">-&gt; 여러 사용자 관점으로 구성하는 것은 외부스키마이다.</span>
④ 논리적인 데이터 독립성을 고려하는 단계는 외부단계와 개념적 단계이다.</p>
</br>

<h4 id="6-아래에서-설명하는-스키마-구조로-가장-적절한-것은">6. 아래에서 설명하는 스키마 구조로 가장 적절한 것은?</h4>
<ul>
<li>모든 사용자 관점을 통합한 조직 전체 관점의 통합적 표현</li>
<li>모든 응용시스템들이나 사용자들이 필요로 하는 데이터를 통합한 조직 전체의 DB를 기술한 것으로 DB에 저장되는 데이터와 그들 간의 관계를 표현하는 스키마</li>
</ul>
<p>① 외부스키마
<span style="color:red">② 개념스키마</span>
<span style="color:green">-&gt; 통합관점의  스키마 구조를 표현한 것을 개념 스키마라고 한다.</span>
③ 내부스키마
④ 논리스키마</p>
<blockquote>
<h4 id="데이터베이스-스키마-구조">데이터베이스 스키마 구조</h4>
</blockquote>
<ul>
<li>외부 스키마
  사용자가 보는 관점에서 데이터 스키마를 정의
  사용자나 응용 프로그램이 필요한 데이터를 정의(View: 사용자가 접근하는 대상)<blockquote>
</blockquote>
</li>
<li>개념 스키마
  사용자 관점의 데이터베이스 스키마를 통합하여 데이터베이스의 전체 논리적 구조를 정의
  전체 데이터베이스의 개체, 속성, 관계, 데이터 타입 등을 정의<blockquote>
</blockquote>
</li>
<li>내부 스키마
  데이터가 물리적으로 어떻게 저장되는지를 정의
  데이터의 저장 구조, 컬럼, 인덱스 등을 정의함</li>
</ul>
</br>


<h4 id="9-아래-시나리오에서-엔터티로-가장-적절한-것은">9. 아래 시나리오에서 엔터티로 가장 적절한 것은?</h4>
<p>S병원은 여러 명의 환자가 존재하고 각 환자의 이름, 주소 등을 관리해야한다.</p>
<p>① 병원
<span style="color:green">-&gt; 병원은 S병원 1개이므로 엔터티로 성립되지 않는다. 엔터티는 2개 이상의 속성과 2개 이상의 인스턴스를 가져 소위 면적으로 표현될 수 있어야 기본적인 엔터티의 자격을 갖췄다고 할 수 있다.</span>
<span style="color:red">② 환자</span>
③ 이름
④ 주소</p>
</br>


<h4 id="12-발생-시점에-따라-구분할-수-있는-엔터티의-유형으로-적절하지-않은-것은">12. 발생 시점에 따라 구분할 수 있는 엔터티의 유형으로 적절하지 않은 것은?</h4>
<p><span style="color:red">① 관계 엔터티</span>
② 행위 엔터티
③ 중심 엔터티
④ 기본 엔터티</p>
<blockquote>
<h4 id="발생-시점에-따른-엔터티-분류">발생 시점에 따른 엔터티 분류</h4>
</blockquote>
<ul>
<li>기본, 키 엔터티</li>
<li>중심 엔터티</li>
<li>행위 엔터티</li>
</ul>
</br>

<h4 id="14-업무에서-필요로-하는-인스턴스에서-관리하고자-하는-의미상-더-이상-분리되지-않는-최소의-데이터-단위는">14. 업무에서 필요로 하는 인스턴스에서 관리하고자 하는 의미상 더 이상 분리되지 않는 최소의 데이터 단위는?</h4>
<p>① 도메인
<span style="color:red">② 속성</span>
<span style="color:green"> -&gt; 데이터 모델링 관점에서 속성을 정의하자면, &quot;업무에서 필요로 하는 인스턴스에서 관리하고자 하는 의미상 더 분리되지 않는 최소의 데이터 단위&quot;로 정의할 수 있다.</span>
③ 엔터티
④ 관계</p>
</br>

<h4 id="15-속성에-대한-설명으로-가장-적절하지-않은-것은">15. 속성에 대한 설명으로 가장 적절하지 않은 것은?</h4>
<p>① 엔터티에 대한 자세하고 구체적인 정보를 나타낸다.
② 하나의 엔터티는 두 개 이상의 속성을 갖는다.
<span style="color:red">③ 하나의 인스턴스에서 각각의 속성은 하나 이상의 속성값을 가질 수 있다.</span>
<span style="color:green">-&gt; 하나의 인스턴스에서 각각의 속성은 한 개의 속성값을 가져야 한다.</span>
④ 속성도 집합이다.</p>
<blockquote>
<h4 id="엔터티테이블-인스턴스행-속성컬럼-속성값의-관계">엔터티(테이블), 인스턴스(행), 속성(컬럼), 속성값의 관계</h4>
</blockquote>
<ul>
<li>한 개의 엔터티는 두 개 이상의 인스턴스 집합이어야 한다.</li>
<li>한 개의 엔터티는 두 개 이상의 속성을 갖는다.</li>
<li>한 개의 속성은 한 개의 속성값을 갖는다.</li>
</ul>
</br>

<h4 id="16-아래에서-수행한-정규화-작업으로-가장-적절한-것은">16. 아래에서 수행한 정규화 작업으로 가장 적절한 것은?</h4>
<img src="https://velog.velcdn.com/images/i-can-do/post/db44b4c8-5356-4df8-88d3-64b6e577cc78/image.jpg" width="70%" height="n%">

<p>① 1차 정규화
<span style="color:red">② 2차 정규화</span>
③ 3차 정규화
④ 4차 정규화</p>
</br>

<h4 id="17-데이터를-조회할-때-빠른-성능을-낼-수-있도록-하기-위해-원래-속성을-계산하여-저장할-수-있도록-만든-속성은">17. 데이터를 조회할 때 빠른 성능을 낼 수 있도록 하기 위해 원래 속성을 계산하여 저장할 수 있도록 만든 속성은?</h4>
<p><span style="color:red">① 파생 속성</span>
<span style="color:green">-&gt; 다른 속성에 영향을 받아 발생하는 속성으로 계산된 값들이 이에 해당한다.</span>
② 기본 속성
③ 설계 속성
④ PK 속성</p>
</br>

<h4 id="20-데이터-모델링의-관계에-대한-설명으로-가장-적절하지-않은-것은">20. 데이터 모델링의 관계에 대한 설명으로 가장 적절하지 않은 것은?</h4>
<p>① 관계는 존재에 의한 관계와 행위에 의한 관계로 구분될 수 있으나 ERD에서는 관계를 연결할 때, 존재와 행위를 구분하지 않고 단일화된 표기법을 사용한다.
② UML에는 클래스다이어그램의 관계 중 연관관계와 의존관계가 있고 이것은 실선과 점선의 표기법으로 다르게 표현이 된다.
③ 연관관계는 항상 이용하는 관계로 존재적 관계에 해당되고, 의존관계는 상대방 클래스의 행위에 의해 관계가 형성되는 행위적 관계에 해당한다.
<span style="color:red">④ 연관관계는 오퍼레이션에서 파라미터 등으로 이용할 수 있고, 의존관계는 소스코드에서 멤버변수로 선언하여 사용할 수 있다.</span>
<span style="color:green">-&gt; 연관관계는 소스코드에서 멤버변수로 선언하여 사용하게 하고
  의존관계는 오퍼레이션에서 파라미터 등으로 이용할 수 있도록 되어 있다.</span></p>
</br>

<h4 id="21-데이터-모델링의-관계에-대한-설명으로-가장-적절하지-않은-것은">21. 데이터 모델링의 관계에 대한 설명으로 가장 적절하지 않은 것은?</h4>
<p>① 관계는 존재적 관계와 행위에 의한 관계로 나누어볼 수 있다.
<span style="color:red">② 관계의 표기법은 관계명, 관계차수, 식별성의 3가지 개념을 사용한다.</span>
<span style="color:green"> -&gt; 관계 표기법은 관계명, 관계차수, 선택성(선택사양)의 3가지 개념으로 표현한다.</span>
③ 부서와 사원 엔터티 간의 &#39;소속&#39;관계는 존재적 관계의 사례이다.
④ 주문과 배송 엔터티 간의 &#39;배송근거&#39;관계는 행위에 의한 관계의 사례이다.
</br></p>
<h4 id="22-아래에서-설명하는-데이터-독립성은">22. 아래에서 설명하는 데이터 독립성은?</h4>
<ul>
<li>데이터베이스의 파일 구조의 변화가 논리스키마에 영향을 주지 않음</li>
<li>데이터베이스의 색인 구조의 변화가 응용 프로그램에 영향을 주지 않음</li>
</ul>
<p>① 논리적 독립성
<span style="color:red">② 물리적 독립성</span>
<span style="color:green">-&gt; 물리적 독립성은 물리 스키마가 변경되어도 논리 스키마에 영향을 주지 않는다. 
  물리적 독립성은 파일 저장 구조의 변경이 논리 스키마와 응용 프로그램에 영향을 주지 않는다.</span>
③ 개념적 독립성
④ 내부적 독립성
</br></p>
<h4 id="25-두-개의-엔터티-사이에서-관계를-도출할-때-확인해야-할-사항을-모두-고른-것은">25. 두 개의 엔터티 사이에서 관계를 도출할 때 확인해야 할 사항을 모두 고른 것은?</h4>
<p>(가) 두 개의 엔터티 사이에 관심 있는 연관규칙이 존재하는가?
(나) 두 개의 엔터티 사이에 정보의 조합이 발생되는가?
(다) 업무기술서, 장표에 관계연결에 대한 규칙이 서술되어 있는가?
(라) 업무기술서, 장표에 관계연결을 가능하게 하는 동사가 있는가?</p>
<p>① (가), (나), (다)
② (가), (나), (라)
③ (가), (다), (라),
<span style="color:red">④ (가), (나), (다), (라)</span>
</br></p>
<h4 id="28-식별자로-가장-적절하지-않은-것은">28. 식별자로 가장 적절하지 않은 것은?</h4>
<p>① 사원번호: number(10) | 주민등록번호 number(13)
<span style="color:red">② 이름: varchar(20) | 사원번호: number(10)</span>
<span style="color:green"> -&gt; 명칭, 내역 등과 같이 이름으로 기술되는 것들은 주식별자로 지정하기에 적절하지 않다. 특히 사람의 이름은 동명이인이 있을 수 있기 때문에 주식별자로서 더더욱 부적절하다.</span>
③ 주민번호: number(13) | 사원번호: number(10)
④ 일련번호: varchar2(10) | 주민등록번호 char(18) | 사원번호: number(10)
</br></p>
<h4 id="30-데이터-모델링에서-비식별자-관계로-연결하는-경우로-가장-적절하지-않은-것은">30. 데이터 모델링에서 비식별자 관계로 연결하는 경우로 가장 적절하지 않은 것은?</h4>
<p>① 엔터티와 엔터티가 1:M 관계의 부모와 자식관계에서 데이터가 부모없이 자식쪽 엔터티의 인스턴스가 먼저 생성될 수 있을 경우 비식별자 관계로 연결해야 한다.
② 부모 엔터티의 인스턴스가 자식 엔터티의 인스턴스보다 먼저 소멸하는 경우 비식별자 관계로 연결해야 한다.
<span style="color:red">③ SQL 문의 조인 관계를 최소화 하는 경우 비식별자 관계로 연결해야 한다.</span>
<span style="color:green"> -&gt; SQL 문의 조인관계를 최소화하기 위해 식별자 관계로 연결해야 한다.</span>
④ 자식 엔터티의 식별자가 부모 엔터티의 주식별자를 상속받아 생성하는 것 보다 별도의 주식별자를 생성하는 것이 더 유리하다고 판단되는 경우 비식별자 관계로 연결해야 한다.
</br></p>
<h4 id="31-아래-식별자에-대한-설명이-올바르게-짝지어진-것은">31. 아래 식별자에 대한 설명이 올바르게 짝지어진 것은?</h4>
<p>(가) 대표성을 가지며, 엔터티 내의 여러 인스턴스 중 하나를 유일하게 구분할 수 있는 식별자
(나) 엔터티 내의 여러 인스턴스 중 하나를 유일하게 구분할 수 있으나, 대표성을 가지지 못하는 식별자
(다) 엔터티 내의 집합을 명확하게 설명할 수 있는 업무적으로 의미가 부여된 식별자
(라)  다른 엔터티로부터 상속되어 정의된 식별자</p>
<p><span style="color:red">③ (가) 주식별자 (나) 보조식별자 (다) 본질식별자 (라) 외부식별자</span>
<span style="color:green"> -&gt; 본질식별자: 업무에 의해 만들어지는 식별자
  외부식별자: 타 엔터티와의 관계를 통해 타 엔터티로부터 받아오는 식별자</span>
</br></p>
<h4 id="33-아래-빈-칸-㉠-㉡-㉢에-해당하는-것은">33. 아래 빈 칸 ㉠, ㉡, ㉢에 해당하는 것은?</h4>
<p>업무 분석을 통해 바로 정의한 속성을 (㉠), 원래 업무상 존재하지는 않지만 설계를 하면서 도출해 내는 속성을 (㉡), 다른 속성으로부터 계산이나 변형이 되어 생성되는 속성을 (㉢)이라고 한다.</p>
<p><span style="color:red">① ㉠ 기본 속성 ㉡ 설계 속성 ㉢ 파생 속성</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[주니어 백엔드 개발자로서의 첫 회사 1년 6개월: 느낀 점과 회고]]></title>
            <link>https://velog.io/@i-can-do/%EC%A3%BC%EB%8B%88%EC%96%B4-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A1%9C%EC%84%9C%EC%9D%98-%EC%B2%AB-%ED%9A%8C%EC%82%AC-1%EB%85%84-6%EA%B0%9C%EC%9B%94-%EB%8A%90%EB%82%80-%EC%A0%90%EA%B3%BC-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@i-can-do/%EC%A3%BC%EB%8B%88%EC%96%B4-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A1%9C%EC%84%9C%EC%9D%98-%EC%B2%AB-%ED%9A%8C%EC%82%AC-1%EB%85%84-6%EA%B0%9C%EC%9B%94-%EB%8A%90%EB%82%80-%EC%A0%90%EA%B3%BC-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 22 Jul 2024 10:52:07 GMT</pubDate>
            <description><![CDATA[<h4 id="후회했던-점">후회했던 점</h4>
<p>퇴사 후 시간이 꽤 흘렀다. 지난 시간들을 돌아보니 후회가 됐던 점이 몇 개 있었다.
또 똑같은 후회를 하고 싶지 않아서, 하지 않기 위해, 퇴사 후 느꼈던 점을 포스팅해보려고 한다.</p>
<blockquote>
</blockquote>
<ol>
<li>왜 이력서 업데이트를 한번도 하지 않았을까?</li>
<li>스프린트 회고를 회사 노션 페이지에&quot;만&quot; 정리했던 점이 후회스럽다.</li>
<li>새롭게 알게 된 지식들은, 회사 노션이 아니라 개인 블로그에 정리했어야했다.</li>
<li>개발 관련 스터디를 나중에 한가해지면 하겠다고 뒤로 미뤘었다(독서도 포함). 잊지말자 한가해지면 나태해져서 더 하기 싫다. 해야겠다고 느낀 그 날 시작해야한다.</li>
</ol>
<p>태그 커뮤니티, 구독, 뱃지, 포스트 예약 발행, 어드민 편의 기능, 푸시 커스텀, 방명록 기능, 후원 기능, 출석 체크, 파티 탭 신규 생성 기타 등등 1년 6개월 동안 참 많은 기능들을 만들었다.
사수가 개발에 직접 참여하지 않았기 때문에, 초기 설계부터 개발까지 직접 했었고, 덕분에 많이 배웠다.</p>
<p>항상 신기능을 개발할 때 마다 많은 고민들을 했었다. 
선택안 A와 B가 있었다면 A를 택했던 이유가 분명히 있었는데 정확하게 기억이 나질 않는다 ㅠㅠ
꼭!! 앞으로는 그 날 바로 블로그에 정리하도록, 최대 3일을 넘지 않도록 습관을 들여야겠다.</p>
<p>블로그에 대충이라도 작성을 했었더라면.. 그 당시 시간이 부족해서 빠르게 개발하고 넘어갔더라도, 
추후 빵꾸난 지식들을 메꿔넣을 수 있었을텐데 그러지 못한 점이 너무 아쉽다. 
꾸준히 작성을 했었다면 이력서 업데이트는 금방 했을텐데 🥲
그 핑계로 아직까지 이력서를 업데이트하지 않고 있는 나 자신이 밉다.</p>
<h4 id="개발자로-근무하면서-느낀-점">개발자로 근무하면서 느낀 점</h4>
<p>백엔드 개발자라는 직업은 나와 잘 맞는 것 같다. 꼼꼼한 성격 덕분에 신입치고는 많은 버그를 줄일 수 있었다. 신규 기능을 개발하면서 기존의 API들과 의존성이 생기게 되었고, 생각하지 못한 버그가 발생할 수도 있었다. 기능을 개발하면서 체크해야 하는 리스트들을 TODO로 작성했고, 잘 작동하는지 문제가 없나 확인하는 시간을 꼭 거쳤다. 시간이 오래 걸린다는 단점이 있었지만, 반복할수록 개발에 필요한 시간은 줄어들었고, 꼼꼼하게 살펴본 덕분에 프로젝트의 전반적인 기능들이 머릿속에 남아 있어 신규 기능들이 잘 작동하도록 도울 수 있었던 것 같다</p>
<h4 id="다짐">다짐</h4>
<p><span style="color: #FFA500;">이력서 업데이트는 6개월 마다 1번!
  스프린트 회고는 무조건이다!
  개발 관련 스터디는 미루지 말자!
</span></p>
<p>후회를 반복하지 말자 🔥</p>
]]></description>
        </item>
    </channel>
</rss>