<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jina__.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 28 Jul 2024 23:20:47 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. jina__.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jina__" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[자바 VS DB]]></title>
            <link>https://velog.io/@jina__/%EC%9E%90%EB%B0%94-VS-DB</link>
            <guid>https://velog.io/@jina__/%EC%9E%90%EB%B0%94-VS-DB</guid>
            <pubDate>Sun, 28 Jul 2024 23:20:47 GMT</pubDate>
            <description><![CDATA[<p>백엔드 개발에서 가장 중요한 것은 데이터를 관리하는 일이라고 할 수 있다.
그리고 데이터를 관리하기 위해 사용하는 것이 바로 데이터베이스, DB이다.</p>
<p>그렇다면 데이터베이스를 사용하기 위해서는 어떻게 해야 할까?</p>
<p>먼저, 어떻게 사용해야 하는지를 알아보기 전에, 자바 세상과 DB 세상이 어떻게 다른지부터 알아보는 것이 필요하다.</p>
<p>자바 세상에서의 객체와 데이터베이스는 지향하는 목적이 다르기 때문에 표현 방법도 다르기 때문이다.</p>
<h2 id="자바-vs-db">자바 VS DB</h2>
<blockquote>
<ol>
<li>JAVA<ul>
<li>객체지향</li>
<li>객체에는 상속 개념이 존재</li>
<li>객체는 참조 사용</li>
</ul>
</li>
</ol>
<ol start="2">
<li>DB<ul>
<li>상속 개념 없음</li>
<li>PK와 FK로 연관 관계 설정</li>
<li>데이터 중심으로 구조화</li>
</ul>
</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jina__/post/2bec1a02-93f7-40b0-94ae-dbbeeb4864c9/image.png" alt=""></p>
<p>위 사진에서 보면 자바 세상에서는 Member의 필드 값으로 Team 타입의 team을 갖고 있지만, DB 세상에서는 TEAM_ID라는 FK를 갖고 있는 것을 볼 수 있다.</p>
<p>그렇다면 이 두 차이는 어떻게 극복해야 할까?</p>
<h2 id="jpa">JPA</h2>
<p> 이 차이를 극복하기 위해 탄생한 것이 바로 JPA이다.</p>
<p> JPA란 Java Persistence API의 약자로, JAVA 진영에서 ORM(Object-Relational Mapping) 기술 표준으로 사용하는 인터페이스의 모음이다.
즉, 자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스이며, 인터페이스이기 때문에 Hibernate, OpenJPA 등이 JPA를 구현한다.
<img src="https://velog.velcdn.com/images/jina__/post/4eddf2f4-0aa9-4694-af30-2e67a1a08801/image.png" alt=""></p>
<p>JPA를 통해 우리는 다음과 같은 장점을 얻게 되었다.</p>
<ul>
<li>SQL 중심적인 개발에서 객체 중심으로 개발</li>
<li>생산성 향상</li>
<li>유지보수 용이</li>
<li>패러다임의 불일치 해결<ul>
<li>객체 지향적인 자바와 데이터 중심인 DB의 관점 차이로 인한 패러다임의 불일치 해결</li>
</ul>
</li>
<li>성능 향상</li>
<li>데이터 접근 추상화와 벤더 독립성<ul>
<li>JPA는 인터페이스이므로 다른 회사의 데이터베이스를 끼워 넣어도 코드 변경 없이 알아서 매핑해준다.</li>
</ul>
</li>
</ul>
<p>결과적으로, JPA를 사용하면 SQL이 아닌 객체 중심으로 개발할 수 있게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] M:N 관계는 왜 안될까?]]></title>
            <link>https://velog.io/@jina__/DB-MN-%EA%B4%80%EA%B3%84%EB%8A%94-%EC%99%9C-%EC%95%88%EB%90%A0%EA%B9%8C</link>
            <guid>https://velog.io/@jina__/DB-MN-%EA%B4%80%EA%B3%84%EB%8A%94-%EC%99%9C-%EC%95%88%EB%90%A0%EA%B9%8C</guid>
            <pubDate>Tue, 23 Jul 2024 02:19:20 GMT</pubDate>
            <description><![CDATA[<h2 id="mn-관계가-안된다고">M:N 관계가 안된다고?</h2>
<p>ERD를 짜다보면 두 테이블의 관계를 M:N으로 정의해야 하는 경우가 생긴다.</p>
<p>예를 들어, 대학교의 데이터베이스를 생각해볼 때 학생과 강의의 테이블을 생각하면, 한 학생이 여러 개의 강의를 수강할 수 있고 한 강의도 여러 학생이 수강하므로 M:N 관계이다.</p>
<p>그런데 두 테이블이 M:N 관계라고 해도 ERD에서 두 테이블의 관계를 명시할 때는 절대 M:N 관계로 나타내면 안되고, 중간 매핑 테이블이 필요하다.</p>
<h2 id="왜-그럴까">왜 그럴까?</h2>
<p>먼저, 매핑 테이블이 없는 관계를 생각해보자.</p>
<p>&lt;학생 테이블&gt;</p>
<table>
<thead>
<tr>
<th>학생 ID (PK)</th>
<th>학생 이름</th>
<th>수강하는 강의 ID (FK)</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>김철수</td>
<td>1, 3</td>
</tr>
<tr>
<td>2</td>
<td>홍길동</td>
<td>3</td>
</tr>
</tbody></table>
<BR/>

<p>&lt;강의 테이블&gt;</p>
<table>
<thead>
<tr>
<th>강의 ID (PK)</th>
<th>강의명</th>
<th>수강하는 학생 ID (FK)</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>운영체제</td>
<td>1</td>
</tr>
<tr>
<td>2</td>
<td>데이터베이스</td>
<td>NULL</td>
</tr>
<tr>
<td>3</td>
<td>자료구조</td>
<td>1, 2</td>
</tr>
</tbody></table>
<BR/>

<p>딱 보면 문제가 있다는 것을 바로 알 수 있다.</p>
<p>일단 원자성을 지키지 않아서 제1 정규화부터 위배되고, 강의 내역을 추가하거나 수정, 삭제를 할 때 두 테이블을 모두 수정해야 한다. 그리고 FK에 NULL 값이 많아져 비효율성을 야기할 수 있다.</p>
<table>
<thead>
<tr>
<th>학생 ID (PK)</th>
<th>학생 이름</th>
<th>수강하는 강의 ID (FK)</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>김철수</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>김철수</td>
<td>3</td>
</tr>
<tr>
<td>2</td>
<td>홍길동</td>
<td>3</td>
</tr>
</tbody></table>
<p>물론 이런 식으로 원자성 문제를 해결할 수 있지만, 이렇게 되면 PK의 의미가 사라진다.</p>
<p>즉, 정리하면 다음과 같은 문제가 발생한다.</p>
<blockquote>
<ol>
<li>원자성을 위배하거나, 원자성을 지키기 위해 레코드를 분리하면 pk의 의미가 없어진다.</li>
<li>삭제 또는 수정 시에 두 테이블을 모두 수정해야 하고, fk에 null이 많아질 수도 있다.</li>
</ol>
</blockquote>
<p>어떻게 해도 문제가 있다는 얘기다. 그래서 우리는 매핑 테이블을 도입한다.</p>
<h2 id="매핑-테이블">매핑 테이블?</h2>
<p>아래와 같이 학생 테이블과 강의 테이블에서 FK를 삭제하고 수강내역 테이블을 추가한다.</p>
<p>&lt;학생 테이블&gt;</p>
<table>
<thead>
<tr>
<th>학생 ID (PK)</th>
<th>학생 이름</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>김철수</td>
</tr>
<tr>
<td>2</td>
<td>홍길동</td>
</tr>
</tbody></table>
<BR/>

<p>&lt;강의 테이블&gt;</p>
<table>
<thead>
<tr>
<th>강의 ID (PK)</th>
<th>강의명</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>운영체제</td>
</tr>
<tr>
<td>2</td>
<td>데이터베이스</td>
</tr>
<tr>
<td>3</td>
<td>자료구조</td>
</tr>
</tbody></table>
<BR/>

<p>&lt;수강 내역 테이블&gt;</p>
<table>
<thead>
<tr>
<th>수강 내역 ID (PK)</th>
<th>학생 ID</th>
<th>강의 ID</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>3</td>
</tr>
<tr>
<td>3</td>
<td>2</td>
<td>3</td>
</tr>
</tbody></table>
<BR/>

<p>이렇게 되면 앞서 언급했던 문제는 모두 사라진다.
즉, M:N 관계 대신 매핑 테이블로 1:N 관계를 두 번 정의함으로써 문제를 해결하는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스프링] DTO]]></title>
            <link>https://velog.io/@jina__/DTO</link>
            <guid>https://velog.io/@jina__/DTO</guid>
            <pubDate>Mon, 22 Jul 2024 07:13:58 GMT</pubDate>
            <description><![CDATA[<p>스프링을 공부하다보면 DTO라는 개념이 등장한다.</p>
<h2 id="dto란">DTO란</h2>
<p>데이터의 &#39;전송용&#39; 객체를 의미하는, Entity의 사본이라고 할 수 있다.
즉, 직접 DB에서 사용하는 Entity와 클라이언트에게 전송하기 위한 객체를 구분하기 위해 사용한다는 것이다.</p>
<blockquote>
<p><strong>[참고] Entity</strong>
DB에서 방금 꺼내 온 데이터 원본이거나, 연산이 끝나서 곧 DB로 들어가 원본이 될 객체</p>
</blockquote>
<p>그렇다면 왜 이렇게 객체를 구분해야 할까?</p>
<h2 id="entity와-dto-구분-이유">Entity와 DTO 구분 이유</h2>
<p>먼저 DTO가 없다고 가정해보자.
DTO가 없다는 뜻은 하나의 객체 또는 데이터가 Repository까지 들어간다는 뜻이다.
만약 하나의 객체, 데이터가 Repository까지 들어가면?</p>
<p><strong>장점</strong></p>
<ul>
<li>관리 포인트가 하나뿐이어서 개발자가 편하다. <del>(개발자만...편함)</del><Br/></li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li><p>스프링 3계층(C/S/R) 간의 이동 시 데이터가 변환될 위험이 존재한다.</p>
</li>
<li><p>클라이언트에게 굳이 전달되지 않아도 되는 데이터(ex. created_at, updated_at과 같은 시스템 활용 데이터)를 포함해서 네트워크 비용만 올라가고 보안 측면에서도 좋지 않다.</p>
</li>
<li><p>클라이언트가 필요한 데이터를 미포함 할 수 있다. (ex. 연관 관계는 없지만 화면에는 같이 뿌려져야 하는 경우, &#39;생년월일 저장 -&gt; 나이 출력&#39;과 같이 연산이 필요한 경우)</p>
</li>
<li><p>단일 책임 원칙에 위배된다.
 1) 클라이언트에 무슨 일이 생겼을 때 DB까지 바꿔야 될 수도 있다. 그런데 DB에 그대로 저장될 데이터는 아니면...?
 2) DB에 무슨 일이 생겼을 때 클라이언트도 바꿔야 될 수도 있다. 예를 들어, DB 칼럼 이름이 바꼈을 때 클라이언트 호출도 바뀌어야 할 수 있다.
  =&gt; <strong>데이터를 옮기는 객체가 하나일 경우, 여러 계층에서 그 객체에 수정을 가하면 단일 책임 원칙이 바로 깨진다.</strong></p>
</li>
</ul>
<BR/>

<p>위 장단점을 보면 DTO를 사용해야 하는 이유가 명확해진다.</p>
<h2 id="그렇다면-entity와-dto를-서로-변환하는-과정은-어디에서-이루어질까">그렇다면, Entity와 DTO를 서로 변환하는 과정은 어디에서 이루어질까?</h2>
<p>먼저 Client에서 전송받은 데이터를 DB까지, 혹은 DB의 데이터를 클라이언트에게 전달하는 과정은 다음과 같다.</p>
<ul>
<li>Client → Controller → Service → Repository → DB</li>
<li>DB → Repository → Service → Controller → Client</li>
</ul>
<p>이 중 어디에서 Entity &lt;-&gt; DTO 변환이 이루어지는 것일까?</p>
<p>사실 이 문제에 대한 주장은 사람마다, 프로젝트마다 다르다.</p>
<h3 id="1-service에서-변환한다는-입장">1) Service에서 변환한다는 입장</h3>
<p>내 입장은 Service에서 변환해야 한다는 입장이다.
Controller에 로직이 있다는 게 이상하고 Repository는 DB에 직접 접근하는 역할을 하는데 DTO 변환까지 책임지면 책임이 너무 커진다는 것이 그 이유이다.</p>
<p>하지만 Controller에서 변환해야 한다는 입장도 만만치 않다.</p>
<h3 id="2-controller에서-변환한다는-입장">2) Controller에서 변환한다는 입장</h3>
<p>&#39;DTO로 변환한다는 것은 결국 클라이언트에 전달해주기 위함인데, 그걸 왜 굳이 Service가 알아야 하냐?&#39;라는 주장을 펼친다.
Service에서 변환한다는 것은 클라이언트가 어떤 필드가 필요한지 Service까지 알려줘야 한다는 뜻인데, 너무 비효율적이라는 입장이다.</p>
<p>실제로 많은 시니어 개발자들이 이 주장을 펼치고 있고, 그 분들의 경험에 반박할 생각은 없다.
하지만 이 주장에 의문이 드는 한 가지가 있다.</p>
<h4 id="만약-어떤-도메인의-service-계층에서-다른-도메인의-repository의-데이터를-가져와서-가공해야-한다면">&quot;만약 어떤 도메인의 Service 계층에서 다른 도메인의 Repository의 데이터를 가져와서 가공해야 한다면?&quot;</h4>
<p>물론 서로 다른 도메인에서 같은 계층끼리 호출하는 경우는 없지만 (만약 그렇다면 설계가 잘못된 거라고 생각) Service가 다른 도메인의 Repository를 부르거나 Controller가 다른 도메인의 Service를 부르는 일은 많이 있다. 그리고 실제로 이런 경우에는 모듈이 독립적으로 잘 설계되었다고 말한다.</p>
<p>그렇다면 이런 경우에 Controller에서 entity를 DTO로 변환하면 너무  복잡해지지 않을까? Controller를 주장하는 사람들의 입장에서 이 질문에 대한 답을 들어보고 싶다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스프링] Gradle Dependency]]></title>
            <link>https://velog.io/@jina__/%EC%8A%A4%ED%94%84%EB%A7%81-Gradle-Dependency</link>
            <guid>https://velog.io/@jina__/%EC%8A%A4%ED%94%84%EB%A7%81-Gradle-Dependency</guid>
            <pubDate>Fri, 19 Jul 2024 07:43:51 GMT</pubDate>
            <description><![CDATA[<p>스프링을 사용하면서, 클래스를 생성할 때마다 매번 getter와 setter 메서드를 추가하는 것이 귀찮았는데, 알고 보니까 Lombok 라이브러리를 추가하면 @Getter, @Setter만으로 끝낼 수 있었다.
그렇다면 라이브러리를 추가해줘야 하는데, 이 라이브러리는 어떻게 추가해야 할까?</p>
<h2 id="buildgradle에-dependency-추가">build.gradle에 dependency 추가</h2>
<pre><code class="language-java">dependencies {
    implementation &#39;org.springframework.boot:spring-boot-starter-web&#39;
    testImplementation &#39;org.springframework.boot:spring-boot-starter-test&#39;
    testRuntimeOnly &#39;org.junit.platform:junit-platform-launcher&#39;
    compileOnly &#39;org.projectlombok:lombok&#39;
    annotationProcessor &#39;org.projectlombok:lombok&#39;
}</code></pre>
<p>먼저 build.gradle에 위와 같이 lombok 라이브러리를 추가해줘야 한다. (아래 두 줄)</p>
<p>그렇다면, lombok을 추가하기 위해 &#39;org.projectlombok:lombok&#39; 이걸 추가하면 된다는 것을 어떻게 알까?</p>
<h2 id="정보는-maven-repository에서">정보는 Maven Repository에서</h2>
<blockquote>
<p>[Maven Repository] <a href="https://mvnrepository.com/">https://mvnrepository.com/</a></p>
</blockquote>
<p>해당 사이트를 들어가서 원하는 라이브러리를 검색한다.
<img src="https://velog.velcdn.com/images/jina__/post/768cac27-dd55-470b-b1fa-71637d12a24d/image.png" alt=""></p>
<p>&#39;lombok&#39;을 검색해서 들어가면
<img src="https://velog.velcdn.com/images/jina__/post/4298a7f4-7912-41e2-a556-d08a2ed66258/image.png" alt=""></p>
<p>위와 같은 창이 나오는데, 원하는 버전을 클릭한다.
그리고 원하는 빌드 도구를 클릭해서 나온 텍스트를 추가하면 된다.
나는 &#39;Gradle (Short)&#39;를 선택했다.
(참고로 Gradle (Short)는 Gradle을 짧게 표현한 것이다.)
<img src="https://velog.velcdn.com/images/jina__/post/9ae5971b-259d-4af8-bb84-c9630b8da766/image.png" alt=""></p>
<p>여기에서 버전 명시를 안하면, gradle이 현재 내 스프링 버전에 적합한 버전으로 알아서 설치해준다고 한다.
(참고로 나는 버전 명시를 안해서 1.18.32 버전으로 설치되었다.)</p>
<p>어쨌든 저렇게 build.gradle에 dependency를 추가하면</p>
<p><img src="https://velog.velcdn.com/images/jina__/post/3e282ea2-dab5-4a01-85e2-099dd7b4704b/image.png" alt=""></p>
<p>이렇게 External Libraries에 lombok이 추가된다.</p>
<p>그런데 여기에서 잠깐, CompileOnly는 뭐지?</p>
<h2 id="스프링-gradle-dependency-키워드">스프링 Gradle Dependency 키워드</h2>
<p>CompileOnly는 Gradle Dependency의 키워드 중 하나이다.
키워드에는 대표적으로 다음과 같은 것들이 있다.</p>
<blockquote>
<p>** implementation:** 프로젝트의 컴파일 시간과 실행 시간 모두에 의존성 추가
<strong>compileOnly:</strong> 컴파일 시간에만 필요한 의존성 추가, 실행시간에는 포함되지 않음
<strong>runtimeOnly:</strong> 실행시간에만 필요한 의존성 추가, 컴파일 시간에는 포함되지 않음
<strong>testImplementation: *<em>테스트 컴파일 시간과 실행 시간에만 필요한 의존성 추가, 주로 단위 테스트나 통합테스트를 위한 라이브러리
*</em>AnnotationProcessor:</strong> 컴파일 단계에서 Annotation에 정의된 일렬의 프로세스를 동작하게 함</p>
</blockquote>
<p>그런데 이때 lombok은 compileOnly이다.
왜지?</p>
<h2 id="getter와-setter는-실행될-때는-필요가-없는-걸까">getter와 setter는 실행될 때는 필요가 없는 걸까?</h2>
<p>그 이유를 찾기 위해 out 폴더에 들어있는 .class를 살펴보았다.</p>
<p>먼저, Accommodation.java 코드는 다음과 같다.</p>
<pre><code class="language-java">// Accommodation.java // lombok 추가 전

public class Accommodation {
    private String name;
    private int minPrice;
}
</code></pre>
<p>그리고 컴파일 하고 나서 생성된 Accommodation.class의 코드를 살펴보면 다음과 같다.</p>
<pre><code class="language-java">// Accommodation.class // lombok 추가 전

public class Accommodation {
    private String name;
    private int minPrice;

    public Accommodation() {
    }
}
</code></pre>
<br/>

<p>이제 build.gradle에 lombok을 추가하고 다음과 같이 lombok의 @Getter와 @Setter를 코드에 추가하였다.</p>
<blockquote>
<p>참고로 lombok은 compileOnly 외에도 annotationProcessor도 추가해줘야 하며, &#39;settings &gt; compile&#39;에서 Enable annotation processing
에 체크해줘야 한다.
그리고 이렇게 dependency를 추가해줘도 lombok이라는 플러그인을 설치해야 한다.</p>
</blockquote>
<pre><code class="language-java">// Accommodation.java // lombok 추가 후

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Accommodation {
    private String name;
    private int minPrice;
}</code></pre>
<p>@Getter와 @Setter을 추가하고 나서, 다시 컴파일 하고 Accommodation.class 파일을 확인하면,</p>
<pre><code class="language-java">// Accommodation.class // lombok 추가 후

public class Accommodation {
    private String name;
    private int minPrice;

    public Accommodation() {
    }

    public String getName() {
        return name;
    }

    public int getMinPrice() {
        return minPrice;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMinPrice(int minPrice) {
        this.minPrice = minPrice;
    }
}</code></pre>
<p>위와 같이 getter와 setter가 추가된 것을 볼 수 있다.
물론 Accommodation.java에는 해당 메서드들이 추가되지 않았다.</p>
<p>즉, @Getter와 @Setter는 컴파일 시간에 getter와 setter 메서드들을 생성하는 것으로 역할이 끝난 것이고, 런타임 시간에는 생성된 getter와 setter를 이용하여 실행을 한다.</p>
<p>따라서 @Getter와 @Setter는 컴파일 시간에만 필요하기 때문에 compileOnly로 lombok 의존성을 추가한 것이다.
필요 없는 런타임 시간에도 의존이 되도록 해버리면 효율성이 너무 떨어지기 때문에...!</p>
<h2 id="정리하자면">정리하자면,</h2>
<p>컴파일 과정을 거치면 out 폴더에 있는 Accommodation.class 파일에 getter와 setter 메서드가 추가된다.
그리고 이후 런타임 과정에서는 Accommodation.class 파일만 필요하므로 더 이상 @Getter와 @Setter는 필요가 없다.
따라서 lombok은 컴파일 과정에서만 필요하므로 compileOnly 키워드를 사용하는 것이 효과적이다. 물론, 빌드 과정에서는 Accommodation.class 파일을 사용하므로  결과물에는 포함된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스프링] @Component, @ComponentScan, @Autowired]]></title>
            <link>https://velog.io/@jina__/%EC%8A%A4%ED%94%84%EB%A7%81-Component-ComponentScan-Autowired</link>
            <guid>https://velog.io/@jina__/%EC%8A%A4%ED%94%84%EB%A7%81-Component-ComponentScan-Autowired</guid>
            <pubDate>Wed, 17 Jul 2024 07:52:49 GMT</pubDate>
            <description><![CDATA[<p>앞서 포스팅한 글에서 IoC와 DI에 대해 다루었다.
스프링이 객체를 생성하고 관리하는 제어권을 개발자한테서 가져가면서 IoC가 일어난다고 언급했다.</p>
<p>그렇다면 스프링은 어떻게 객체를 생성하고 관리하는 것이며, 개발자는 이걸 어떻게 사용할까?</p>
<h2 id="component로-스프링-빈을-생성할-클래스-명시">@Component로 스프링 빈을 생성할 클래스 명시</h2>
<p>아무리 스프링이 객체를 알아서 생성한다고 해도 개발자가 아무것도 하지 않았는데 혼자 그냥 생성할 수는 없다.</p>
<p>개발자는 스프링한테 &#39;어떤 클래스&#39;에서 객체를 생성해달라고 말을 해야 한다.</p>
<p>그리고 그렇게 말하는 수단으로 보통 &#39;@Component&#39;을 사용한다.</p>
<pre><code class="language-java">import org.springframework.stereotype.Component;

@Component
public class House {

    private String name;

    public House() {
        name = &quot;B house&quot;;
        System.out.println(&quot;Created House Bean&quot;);
    }

    public String getName() {
        return name;
    }
}</code></pre>
<p>이런 식으로 클래스 위에 @Component를 붙여주면, 해당 클래스의 인스턴스가 스프링 빈으로 등록된다.</p>
<p>여기에서는 House 클래스의 인스턴스가 스프링 빈으로 등록돼서 스프링 컨테이너에 저장된다.</p>
<h2 id="그럼-component만-붙여주면-스프링-빈-생성은-끝">그럼 @Component만 붙여주면 스프링 빈 생성은 끝?</h2>
<p>아쉽게도 그렇지 않다.</p>
<p>스프링이 맨 처음 실행되면 어떤 클래스에 @Component가 붙어있는지 찾는 과정을 거쳐야 한다.</p>
<p>그렇게 @Component가 붙어있는 클래스를 찾아야, 해당 클래스에서 생성된 객체를 스프링 빈에 등록할 수 있다.</p>
<p>그리고 이렇게 클래스를 찾는 과정은 @ComponentScan을 통해서 진행한다.</p>
<p>@ComponentScan은 아래와 같이 최상위 인터페이스인 SpringBootApplication의 위에 등록되어 있다.</p>
<pre><code class="language-java">@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ...</code></pre>
<br/>

<h2 id="스프링-빈-생성은-끝났고어떻게-가져다-쓰지">스프링 빈 생성은 끝났고...어떻게 가져다 쓰지?</h2>
<p>스프링 컨테이너에 저장된 스프링 빈을 사용하기 위해서는 DI를 해야하는데, 이것을 위해서 @Autowired를 사용한다.</p>
<pre><code class="language-java">import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Person {

    House house;

    @Autowired
    public Person (House house){
        this.house = house;
        System.out.println(&quot;buy &quot; + house.getName());
    }
}</code></pre>
<p>이렇게 메서드 위에 @Autowired를 붙이면 메서드의 인자로 개발자가 넘겨주지 않아도, 스프링이 스프링 컨테이너에 있는 빈 중에 타입이 맞는 것을 알아서 넘겨준다.</p>
<p>즉, 이렇게 스프링 빈을 가져다 쓸 수 있는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스프링] IoC? DI? 컨테이너? 빈?]]></title>
            <link>https://velog.io/@jina__/%EC%8A%A4%ED%94%84%EB%A7%81-IoC-DI-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EB%B9%88</link>
            <guid>https://velog.io/@jina__/%EC%8A%A4%ED%94%84%EB%A7%81-IoC-DI-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EB%B9%88</guid>
            <pubDate>Tue, 16 Jul 2024 07:45:52 GMT</pubDate>
            <description><![CDATA[<p>스프링을 처음 시작하면 이 용어들을 마주하게 된다.</p>
<p>그리고 IoC를 번역한 &#39;제어의 역전&#39;, DI를 번역한 &#39;의존성 주입&#39; 이런 말을 들으면 더 미궁으로 빠지고...이게 대체 뭔 소린가 싶게 된다.</p>
<p>하지만 생각보다 이 개념들은 어렵지 않다.</p>
<h2 id="먼저-ioc부터-알아보자">먼저, IoC부터 알아보자.</h2>
<blockquote>
<p>IoC(Inversion of Control)를 한 마디로 나타내면?
<strong>객체를 관리하는 주도권을 개발자한테서 스프링이 가져가는 것</strong></p>
</blockquote>
<p>기존에 자바에서는</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        Car gasCar = new GasCar();
        Car electricCar = new ElectricCar();
        Car hydrogenCar = new HydrogenCar();

        gasCar.charge();
        electricCar.charge();
        hydrogenCar.charge();
    }
}</code></pre>
<p>이런 식으로 개발자가 직접 객체를 생성하고 관리해야 한다.</p>
<p>그런데 매번 이렇게 개발자가 하는 일이 귀찮고 번거로울 수 있다...
그래서 이 일을 스프링에게 넘겨버리는 것이다.</p>
<p><strong>즉, 스프링이 알아서 객체를 생성하고 관리하는 것!</strong></p>
<p>이것이 IoC이다.
<BR/></p>
<p>그런데 스프링은 객체를 생성하면 어디다가 담아둘까?
그냥 여기저기 아무데나 두면 관리하기 힘들텐데?</p>
<p>그래서 등장한 것이 &#39;컨테이너&#39;이다.</p>
<h2 id="컨테이너">컨테이너</h2>
<blockquote>
<p><strong>컨테이너란?</strong>
스프링이 관리하는 객체를 담는 곳</p>
</blockquote>
<p>그냥 쉽게 말해서 객체를 담는 상자라고 보면 된다. 
이때 객체는 일반적인 객체가 아닌 스프링이 생성하고 관리하는 객체이고...!</p>
<p>그렇다면 이렇게 스프링이 관리하는 객체와 지금까지 말한 객체를 구별하여 말할 수는 없을까?</p>
<h2 id="스프링-빈">스프링 빈</h2>
<p>사실 스프링이 생성하고 관리하는 객체는 일컫는 용어가 따로 있다.
그것이 바로 <strong>&quot;스프링 빈&quot;</strong>이다.
<br/></p>
<p>그렇다면 IoC, 컨테이너, 빈은 이제 무슨 소리인지 알겠고, 남은 건 DI (Dependency Injection)이다.</p>
<h2 id="di-dependency-injection">DI (Dependency Injection)</h2>
<p>개발자가 생성하고 관리하던 객체를 스프링이 맡아서 관리하게 되었고... 이게 IoC이고... 이렇게 스프링이 관리하는 객체를 빈이라고 하고, 빈을 담는 상자를 컨테이너라고 한다.</p>
<p>지금까지 한 얘기를 요약한 것이다.</p>
<p>그런데 스프링이 객체를 맡아서 관리하면 개발자는 이걸 어떻게 갖다쓰지?</p>
<p>여기에서 나온 개념이 DI이다.</p>
<blockquote>
<p><strong>DI란?</strong>
개발자가 스프링 컨테이너가 관리하는 객체(빈)를 가져가서 사용하는 것</p>
</blockquote>
<p>조금 어렵게 말하면, &#39;IoC를 구현하기 위해서 객체를 주입받는 것&#39;을 DI라고 할 수 있다.</p>
<p>즉, IoC로 인해 DI의 개념도 등장한 것이고, DI가 등장하면서 비로소 개발자는 스프링에게 객체 관리를 맡기고 이걸 갖다쓰기만 할 수 있는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[좋은 객체 지향 설계의 5가지 원칙 - SOLID]]></title>
            <link>https://velog.io/@jina__/%EC%A2%8B%EC%9D%80-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84%EC%9D%98-5%EA%B0%80%EC%A7%80-%EC%9B%90%EC%B9%99-SOLID</link>
            <guid>https://velog.io/@jina__/%EC%A2%8B%EC%9D%80-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84%EC%9D%98-5%EA%B0%80%EC%A7%80-%EC%9B%90%EC%B9%99-SOLID</guid>
            <pubDate>Mon, 15 Jul 2024 13:51:51 GMT</pubDate>
            <description><![CDATA[<p>블로그 제목을 어떻게 할까 고민하던 중, 마침 듣고 있던 김영한님 강의에서 SOLID를 다루고 있길래...이렇게 제목을 <del>베껴...아니</del> 차용해왔다.</p>
<h2 id="solid">SOLID?</h2>
<p>먼저, SOLID란 무엇일까?</p>
<p>사실 SOLID라는 개념은 정말 많이 돌아다니고, 많은 사람들이 학습하는 개념이지만 제대로 알고 있는 사람은 많지 않다.</p>
<p>실제로 책에서 소개하는 SOLID 개념을 살펴보면 외계어가 따로 없다.</p>
<blockquote>
<ul>
<li>S (SRP, 단일 책임 원칙): 한 클래스는 하나의 책임만 가져야 한다.</li>
</ul>
</blockquote>
<ul>
<li>O (OCP, 개방-폐쇄 원칙): 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.</li>
<li>L (LSP, 리스코프 치환 원칙): 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.</li>
<li>I (ISP, 인터페이스 분리 원칙): 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.</li>
<li>D (DIP, 의존관계 역전 원칙): 프로그래머는 추상화에 의존해야 하며, 구체화에 의존하면 안된다.</li>
</ul>
<p>처음 보면 이게 뭔소린가 싶고, 자연스럽게 다시 떠나보내게 된다.
<del>나 또한 그랬다. 나는 정처기 할 때 이 개념을 제대로 처음 봤는데, 조용히 다음 장으로 넘기며 안나오길 기도했다...</del></p>
<br/>
개발자에게 이해하기에 가장 쉬운 도구는 '코드'이다.
위 개념들을 '코드'를 통해서 제대로 이해해보자.


<h2 id="1-s-srp-단일-책임-원칙">1. S (SRP, 단일 책임 원칙)</h2>
<p>말 그대로 정말 한 클래스는 하나의 책임을 가져야 한다는 뜻인데, 이렇게만 말해버리면 앞의 설명과 다를 게 없다.</p>
<p>대체 책임이란 무엇일까?</p>
<p>이게 굉장히 애매하다.
따라서 우리는 <strong>&#39;변경&#39;</strong>을 중요한 기준으로 본다. 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것으로 판단한다.</p>
<h3 id="먼저-srp를-따르지-않은-코드부터-살펴보자">먼저 SRP를 따르지 않은 코드부터 살펴보자</h3>
<p>참고로 아래 코드에서 PediaStudent 클래스는 다음과 같은 기능을 수행하고 있다.</p>
<ul>
<li>takeQrcode(): qr코드를 인증하는 메소드(알파코 1팀과 알파코 2팀이 사용)</li>
<li>startEducationTime() : 알파코 1팀이 정규교육시간을 시작하는 메소드</li>
<li>startSelfStudyTime() : 알파코 2팀이 자율학습시간을 시작하는 메소드</li>
</ul>
<pre><code class="language-java">class PediaAlpha{
    String name;
    String positon;

    PediaAlpha(String name, String position) {
        this.name = name;
        this.positon = position;
    }

    // Qr코드를 찍는 메서드 (두 팀에서 공유하여 사용)
    void takeQrcode() {
        // ...
    }

    // 정규교육 시작 (알파코 1팀에서 사용)
    void startEducationTime() {
        // ...
        this.takeQrcode();
        // ...
    }

    // 자율학습 시작  (알파코 2팀에서 사용)
    void startSelfStudyTime() {
        // ...
        this.takeQrcode();
        // ...
    }
}</code></pre>
<p>위 코드에서 takeQrcode()라는 메서드를 startEducationTime() 메서드와 startSelfStudyTime() 메서드에서 공유하고 있다.</p>
<p>그런데 만약 startEducationTime() 메서드를 사용하는 알파코 1팀이 takeQrcode() 메서드를 변경해야 해서 변경한다면...?</p>
<p>알파코 2팀에서 사용하던 startSelfStudyTime() 메서드에도 영향을 미치고 이는 곧 심각한 문제로 이어질 수도 있다.</p>
<p>하나를 변경했는데, 여러 곳에 영향을 미친다는 이 얘기가 바로 SRP를 따르지 않았다는 뜻이다.</p>
<p>따라서 아래와 같이 코드를 변경해야 한다.</p>
<h3 id="srp를-따른-코드">SRP를 따른 코드</h3>
<pre><code class="language-java">
class PediaAlpha {
    private String name;
    private String positon;

    PediaAlpha(String name, String position) {
        this.name = name;
        this.positon = position;
    }

    // 정규교육시간을 시작하는 메소드 (알파코 1팀에서 사용)
    void startEducationTime() {
        // ...
        new EducationTimeStarter().startEducationTime();
        // ...
    }

    // 자율학습시간을 시작하는 메소드 (알파코 2팀에서 사용)
    void startSelfStudyTime() {
        // ...
        new SelfStudyTimeStarter().startSelfStudyTime();
        // ...
    }
}

// 알파코 1팀에서 사용되는 전용 클래스
class EducationTimeStarter {
    // qr코드를 인증하는 메서드
    void takeQrcode() {
        // ...
    }
    void startEducationTime() {
        // ...
        this.takeQrcode();
        // ...
    }
}

// 알파코 2팀에서 사용되는 전용 클래스
class SelfStudyTimeStarter {
    // qr코드를 인증하는 메서드
    void takeQrcode() {
        // ...
    }
    void startSelfStudyTime() {
        // ...
        this.takeQrcode();
        // ...
    }
}</code></pre>
<p>startEducationTime() 메서드와 startSelfStudyTime() 정의하는 클래스를 따로 따로 정의하고, 그 안에 takeQrcode() 메서드도 각각 정의한다.</p>
<p>이렇게 되면 알파코 1팀이 takeQrcode() 메서드를 변경해도 2팀에는 영향을 미치지 않는다.</p>
<p>즉, 단일 책임 원칙을 잘 따랐다고 할 수 있다.</p>
<h2 id="2-o-ocp-개방-폐쇄-원칙">2. O (OCP, 개방-폐쇄 원칙)</h2>
<p>&#39;확장에는 열려 있으나 변경에는 닫혀 있어야 한다.&#39;
이게 진짜 무슨 외계어인지 모르겠다...</p>
<p>이걸 풀어서 좀 더 쉽게 말하면 다음과 같이 말할 수 있다.</p>
<blockquote>
<p>기능을 추가할 때는 추가하는 부분 추가만 해야 하며, 기존 코드를 변경하면 안된다.</p>
</blockquote>
<p>물론 이렇게 말해도 잘 와닿지 않을 것이다.
그렇다면 우리가 이해할 수 있는 수단은 역시 코드이다.</p>
<h3 id="ocp가-지켜지지-않은-코드">OCP가 지켜지지 않은 코드</h3>
<pre><code class="language-java">// Car 클래스
public class Car {
    String type;

    public Car(String type) {
        this.type = type;
    }
    public void charge(){
        if(type.equals(&quot;GasCar&quot;)){
            System.out.println(&quot;기름을 주유합니다.&quot;);
        }
        else if(type.equals(&quot;ElectricCar&quot;)) {
            System.out.println(&quot;전기차를 충전합니다.&quot;);
        }
        // 다른 차를 추가하려면 아래와 같이 추가해줘야 함
        else if(type.equals(&quot;HydrogenCar&quot;)){
            System.out.println(&quot;수소차를 충전합니다.&quot;);
        }
    }
}

// Main
public class Main {
    public static void main(String[] args) {
        Car gasCar = new Car(&quot;GasCar&quot;);
        Car electricCar = new Car(&quot;ElectricCar&quot;);
        Car hydrogenCar = new Car(&quot;HydrogenCar&quot;); // 수소차 추가

        gasCar.charge();
        electricCar.charge();
        hydrogenCar.charge(); // 수소차 추가
    }
}</code></pre>
<p>위 코드에서 새로운 차인 수소차를 추가하려면 기존 코드인 Car 클래스의 charge 메서드를 수정해야 한다.
새로운 차가 추가될 때마다 매번 코드를 변경해줘야 한다는 것은 상당히 번거로운 일이고 유지보수에도 최악이다.</p>
<p>바로 이렇게 기존 코드, 정확히는 클라이언트 코드를 수정한다는 것이 OCP에 위배된다.</p>
<p>따라서 아래와 같이 OCP를 지킬 수 있도록 수정해야 한다.</p>
<h3 id="ocp가-지켜진-경우">OCP가 지켜진 경우</h3>
<pre><code class="language-java">// Car 인터페이스
public interface Car {
    void charge();
}

// ElectricCar 클래스
public class ElectricCar implements Car{
    @Override
    public void charge() {
        System.out.println(&quot;전기차를 충전합니다.&quot;);
    }
}

// GasCar 클래스
public class GasCar implements Car{
    @Override
    public void charge() {
        System.out.println(&quot;기름을 주유합니다.&quot;);
    }
}

// HydrogenCar 클래스 // 다른 차 추가
public class HydrogenCar implements Car{
    @Override
    public void charge() {
        System.out.println(&quot;수소차를 충전합니다.&quot;);
    }
}

// Main
public class Main {
    public static void main(String[] args) {
        Car gasCar = new GasCar();
        Car electricCar = new ElectricCar();
        Car hydrogenCar = new HydrogenCar(); // 수소차 추가

        gasCar.charge();
        electricCar.charge();
        hydrogenCar.charge(); // 수소차 추가
    }
}</code></pre>
<p>위 코드와 같이 다형성 및 상속을 통해서 OCP를 지킬 수 있다.</p>
<p>이게 왜 OCP를 지킨 코드인지 이해가 잘 안되시는 분들을 위해 부연 설명을 하자면,</p>
<blockquote>
<p>이 코드는 수소차를 추가해야 할 때, 기존 클라이언트 코드를 수정하는 것이 아니라 HydrogenCar 클래스를 추가하기만 하면 된다.</p>
</blockquote>
<p>처음 코드도 그냥 if문 조건을 추가한 것이 아니냐고 반문할 수도 있는데, 기존 클래스를 손봐야 한다는 것은 엄연히 추가가 아니고 수정이다.</p>
<h2 id="3-l-lsp-리스코프-치환-원칙">3. L (LSP, 리스코프 치환 원칙)</h2>
<p>리스코프... 괜히 사람 이름이 더 어렵게 느껴지게 만든다.</p>
<p>하지만 이것도 한마디로 풀어쓰자면 다음과 같다.</p>
<blockquote>
<p>자식은 부모가 정의한 대로 구현되어야 한다.</p>
</blockquote>
<p>즉, 어떤 인터페이스를 구현한 하위 인스턴스는 딱 인터페이스에 있는 만큼만 구현해야 한다는 뜻이다.</p>
<p>인터페이스는 &quot;공통 규약&quot;인데, 하위 인스턴스가 그 이상을 구현하면 그 의미가 퇴색된다.</p>
<p>이것도 코드로 더 자세히 보자.</p>
<h3 id="lsp가-지켜지지-않은-경우">LSP가 지켜지지 않은 경우</h3>
<pre><code class="language-java">interface Parent {
    void A();
    void B();
}

public class Child implements Parent {
    public void A() {}
    public void B() {}
    public void C() {}
    public void D() {}
}</code></pre>
<p>분명 부모 인터페이스에는 A와 B만 있는데 자식 클래스가 멋대로 C와 D 메서드까지 구현해버렸다.</p>
<p>이런 걸 우리는 LSP를 위반했다고 한다.</p>
<h3 id="그렇다면-lsp를-지키려면">그렇다면 LSP를 지키려면?</h3>
<pre><code class="language-java">interface Parent1 {
    void A();
    void B();
}

interface Parent2 {
    void C();
    void D();
}

public class Child implements Parent1, Parent2 {
    public void A() {}
    public void B() {}
    public void C() {}
    public void D() {}
}</code></pre>
<p>C와 D 메서드를 갖는 다른 인터페이스도 부모로 껴주자,,</p>
<p>여기에서 그냥 Parent1이 A, B, C, D 모두 갖고 Child가 Parent1만 상속받으면 되지 않느냐는 의문이 생길 수도 있는데, 타당한 의문이다.</p>
<p>그렇게 해도 LSP는 지켜진다.
그런데 굳이 이렇게 한 이유를 설명하라고 하면, 아래 ISP 때문이다.</p>
<h2 id="4-i-isp-인터페이스-분리-원칙">4. I (ISP, 인터페이스 분리 원칙)</h2>
<p>&#39;특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다&#39;
......</p>
<p>이것도 개념만 보면 대체 뭔 소린가 싶다.
좀 더 쉽게 풀어보자.</p>
<blockquote>
<p>자식 클래스는 자신이 사용하는 메서드만 존재하는 인터페이스를 상속해야 한다.
이렇게 하기 위해 인터페이스는 너무 비대해지면 안된다.</p>
</blockquote>
<p>아직도 무슨 소리인지 모르겠다면 아래 코드를 보자.</p>
<h3 id="isp가-지켜지지-않은-경우">ISP가 지켜지지 않은 경우</h3>
<pre><code class="language-java">interface Car {
    String PowerOn();
    void lockWindow();
    String speakAI();
}

class Avante implements Car {
    String PowerOn(){
        ...
    }
    void lockWindow() {
        ...
    }
    String speakAI() {
        return &quot;지원하지 않는 기능입니다.&quot;;
    }
}

class Grandeur implements Car {
    String PowerOn(){
        ...
    }
    void lockWindow() {
        ...
    }
    String speakAI() {
        ...
    }
}</code></pre>
<p>위 코드에서 Avante 클래스는 speakAI() 메서드가 필요가 없다.
하지만 Car라는 인터페이스를 상속받아서 어쩔 수 없이 구현해야 한다.</p>
<p>뭔가 문제가 있다고 느껴지지 않나?</p>
<p>Car 인터페이스가 너무 많은 인터페이스를 갖고 있어서 생긴 문제이다.</p>
<p>따라서 다음과 같이 이를 해결할 수 있다.</p>
<h3 id="isp가-지켜진-경우">ISP가 지켜진 경우</h3>
<pre><code class="language-java">interface Car {
    String PowerOn();
    void lockWindow();
}

interface AICompanion {
    String speakAI();
}

class Avante implements Car {
    String PowerOn(){
        ...
    }
    void lockWindow() {
        ...
    }
}

class Grandeur implements Car, AICompanion {
    String PowerOn(){
        ...
    }
    void lockWindow() {
        ...
    }
    String speakAI() {
        ...
    }
}</code></pre>
<p>Car의 기본 기능은 Car 인터페이스에 구현해두고, Grandeur의 추가 기능은 AICompanion이라는 인터페이스를 생성하여 추가 구현해준다.</p>
<p>이렇게 하면 Avante는 사용하지 않는 메서드를 굳이 구현할 필요가 없다.</p>
<h2 id="5-d-dip-의존관계-역전-원칙">5. D (DIP, 의존관계 역전 원칙)</h2>
<p>&#39;프로그래머는 추상화에 의존해야 하며, 구체화에 의존하면 안된다.&#39;</p>
<p>알듯 말듯한...무슨 소리인가 싶다.
쉽게 말해서, 아래와 같다.</p>
<blockquote>
<p>구현 클래스에 의존하지 말고, 인터페이스에 의존해야 한다.
즉, <strong>역할에 의존해야 한다</strong>는 뜻!</p>
</blockquote>
<p>잘 모르겠으면 이것도 코드로 보자.</p>
<h3 id="dip를-지키지-않은-코드">DIP를 지키지 않은 코드</h3>
<pre><code class="language-java">public class WindowsXPComputer { 
    private final StandardKeyboard keyboard;
    private final BallMouse mouse; 

    public Windows98Machine() { 
        mouse = new BallMouse(); 
        keyboard = new StandardKeyboard(); 
    } 
}</code></pre>
<p>WindowsXPComputer 클래스는 StandardKeyboard와 BallMouse라는 구현 클래스에 의존하고 있다.</p>
<p>그런데 만약 볼마우스가 고장난다면? 단종되어서 더 이상 팔지 않는다면?</p>
<p>이 코드에서는 볼마우스가 사라지면 WindowsXPComputer도 고장난다.
따라서 WindowsXPComputer에게 다양한 키보드와 마우스를 선택해 사용할 수 있도록 해야 한다.</p>
<h3 id="dip가-지켜진-경우">DIP가 지켜진 경우</h3>
<pre><code class="language-java">
public class WindowsXPComputer {
    private  Keyboard keyboard;
    private  Mouse mouse;

    public void WindowsXPComputer(Keyboard keyboard, Mouse mouse) {
        this.keyboard = keyboard;
        this.mouse = mouse;
    }
}

public interface Mouse {
    void move();
}

public class VerticalMouse implements Mouse {
    public void move() {}
}

public class BallMouse implements Mouse {
    public void move() {}
}

public interface Keyboard {
    // 키보드 관련 메서드 정의
}

public class StandardKeyboard implements Keyboard {
    // StandardKeyboard의 구현
}

public class MechanicalKeyboard implements Keyboard {
    // MechanicalKeyboard의 구현
}
</code></pre>
<p>이런 식으로 WindowsXPComputer 클래스가 StandardKeyboard와 BallMouse라는 구현 클래스가 아닌 Keyboard와 Mouse라는 인터페이스에 의존하게 되면 위의 문제는 사라진다.</p>
<p>이걸 DIP를 지켰다고 한다.</p>
<h2 id="solid는-이제-알겠고">SOLID는 이제 알겠고...</h2>
<p>추가로 의존성과 응집도, 결합도 개념을 살펴보자.
갑자기 왜 의존성, 응집도, 결합도를 살펴보는 건가 싶을 수도 있다.</p>
<p>하지만 이 세 특징은 결국 앞서 살펴본 SOLID 원칙과 연결되어 있다.</p>
<p>그 예로 SRP만 집어서 설명을 해보자면, SRP를 지킨다는 것은 해당 프로그램에서 한 클래스 내의 응집도가 높다는 것이고, 클래스끼리는 관련이 적다는 것이므로 결합도가 낮다는 것을 의미한다. 그렇다면 당연히 의존성도 낮을 것이다.</p>
<p>결국 다 객체지향 원칙을 다루는 만큼, SOLID 원칙과 의존성, 응집도, 결합도는 따로 학습할 수 없는 개념이므로 여기에서 한 번에 다루기로 하자.</p>
<h3 id="의존성">의존성</h3>
<p>의존성은 하나의 모듈 또는 클래스가 다른 모듈이나 클래스를 필요로 하는 정도를 의미한다.</p>
<p>즉, 특정 객체가 다른 객체를 사용하거나, 특정 객체의 기능에 의존하여 동작하는 관계를 나타낸다.</p>
<pre><code class="language-java">class Engine {
    void start() {
        System.out.println(&quot;Engine started&quot;);
    }
}

class Car {
    private Engine engine;

    Car() {
        engine = new Engine(); // Car는 Engine에 의존적
    }

    void startCar() {
        engine.start(); // Car는 Engine의 메소드에 의존적
    }
}</code></pre>
<p>위 코드에서 Car 클래스는 Engine 클래스에 강하게 의존적이다. Engine이 없으면 Car는 동작할 수 없기 때문이다.</p>
<p>객체지향 설계에서는 의존성을 최소화하여 모듈 간의 독립성을 높이고, 유지보수와 확장을 용이하게 한다.</p>
<p>응집도와 결합도는 모듈의 독립성을 측정하는 기준이라고 할 수 있다.</p>
<p>그렇다면, 이제 응집도와 결합도에 대해 알아보자.</p>
<h3 id="응집도와-결합도">응집도와 결합도</h3>
<h3 id="1-응집도">1) 응집도</h3>
<blockquote>
<p>응집도는 한 모듈 내의 구성 요소 간의 밀접한 정도를 의미한다.</p>
<p>객체지향의 관점에서 응집도는 객체 또는 클래스에 얼마나 관련 있는 책임들을 할당했는지를 나타낸다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jina__/post/976354fd-618a-4b60-984b-452ffab2ea71/image.png" alt=""></p>
<h4 id="응집도가-낮다면">응집도가 낮다면?</h4>
<p>모듈 내부에 서로 관련 없는 함수나 데이터들이 존재하거나 관련성이 적은 여러 기능들이 서로 다른 목적을 추구하며 산재해 있다.</p>
<h4 id="응집도가-높다면">응집도가 높다면?</h4>
<p>하나의 모듈 안에 함수나 데이터와 같은 구성 요소들이 하나의 기능을 구현하기 위해 필요한 것들만 배치되어 있고 긴밀하게 협력한다.
<strong>즉, 응집도가 높을 수록 독립성이 높은 모듈이며 좋은 소프트웨어는 높은 응집도를 유지해야 한다.</strong></p>
<h3 id="2-결합도">2) 결합도</h3>
<blockquote>
<p>결합도는 모듈간의 상호 의존 정도를 의미한다.</p>
<p>객체지향의 관점에서 클래스나 메소드가 적절한 수준의 관계만을 유지하고 있는지를 나타낸다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jina__/post/ccc292ce-6210-4768-8307-03809fe7da40/image.png" alt=""></p>
<h4 id="결합도가-높다면">결합도가 높다면?</h4>
<p>결합도가 높다는 것은 다른 클래스와의 연관성이 높다는 것을 의미한다.</p>
<p>이는 한 클래스를 수정할 때 연관된 다른 클래스도 변경해야 할 가능성이 높아진다는 것을 뜻한다. </p>
<p>예를 들어, 자동차의 경우를 생각해보면, 핸들, 바퀴, 엔진 등 여러 모듈이 서로 의존되어 결합된 상태인데, 만약 자동차의 결합도가 너무 높게 설계되었다면, 바퀴를 교체하는데 엔진까지 모두 바꿔야 하는 상황이 발생할 수 있다.
(뭔가 SOLID 원칙에서 다룬 듯한 느낌이 든다면 제대로 이해한 것이 맞다.)</p>
<h4 id="결합도가-낮다면">결합도가 낮다면?</h4>
<p>모듈 간의 의존성이 줄어들어, 하나의 모듈을 변경하더라도 다른 모듈에 미치는 영향을 최소화할 수 있다. 
그리고 이것은 유지보수성과 확장성을 높이는 중요한 요소이다.
<strong>즉, 좋은 소프트웨어는 낮은 결합도를 가지고 있다.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우아한 남매들] 배달의 만족 KPT 회고]]></title>
            <link>https://velog.io/@jina__/%EC%9A%B0%EC%95%84%ED%95%9C-%EB%82%A8%EB%A7%A4%EB%93%A4-%EB%B0%B0%EB%8B%AC%EC%9D%98-%EB%A7%8C%EC%A1%B1-KPT-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jina__/%EC%9A%B0%EC%95%84%ED%95%9C-%EB%82%A8%EB%A7%A4%EB%93%A4-%EB%B0%B0%EB%8B%AC%EC%9D%98-%EB%A7%8C%EC%A1%B1-KPT-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 15 Jul 2024 08:10:54 GMT</pubDate>
            <description><![CDATA[<h2 id="배달의-만족">배달의 만족?</h2>
<p>예상했던 대로, 우아한형제들의 &#39;배달의 민족&#39; 서비스를 참고하여 진행한 프로젝트이다.
<del>배달의 민족으로 잘못 읽으신 분들께 심심한 사과의 말씀을...</del></p>
<p>스프링이나 프론트엔드 없이 순수하게 자바만 사용하여 진행된 프로젝트이며, 그런 만큼 자바의 이해 자체에 초점이 맞춰져 진행되었다.</p>
<blockquote>
<p>[우아한 남매들] 배달의 만족
<a href="https://github.com/woowahan-nammaes/SatisfactionOfDelivery">https://github.com/woowahan-nammaes/SatisfactionOfDelivery</a></p>
</blockquote>
<h3 id="기능-및-프로세스">기능 및 프로세스</h3>
<p>4일 동안 진행된 프로젝트인 만큼, 정말 기본 중의 기본 기능만 집중해서 구현하였다.
<img src="https://velog.velcdn.com/images/jina__/post/71f7a8db-ae4d-4f7f-8fdb-f5c52b5e0ddc/image.png" alt=""></p>
<p>주요 기능은 다음과 같다.</p>
<ul>
<li>회원 가입 기능</li>
<li>로그인 기능</li>
<li>로그아웃 기능</li>
<li>가게 카테고리별 조회 기능</li>
<li>가게별 메뉴 조회 기능</li>
<li>메뉴 주문 기능</li>
<li>주문 기록 조회 기능</li>
</ul>
<p>그리고 추가적으로 구현한 부가 기능은 다음과 같다.</p>
<ul>
<li>회원가입 정보 유효성 검사</li>
<li>사용자 입력 유효성 검사<BR/>

</li>
</ul>
<h2 id="kpt-회고">KPT 회고</h2>
<p>그리고 해당 프로젝트를 진행하면서 느낀 점을 KPT 회고 형식으로 남기고자 한다.</p>
<h2 id="k---keep">K - Keep</h2>
<ul>
<li>구현 전에 팀원들과 모두 요구사항들을 정리하고 설계를 끝낸 다음, 각자 개발을 시작하였다.</li>
<li>개발 도중 이슈나 고민거리가 생기면 즉각적으로 팀원들과 논의하였다.</li>
<li>도메인 별로 나누어 MVC 패턴에 맞춰 개발을 진행했다.</li>
<li>객체지향 개념을 지키고자 했으며, SOLID 원칙 중 특히 SRP는 지키고자 했다.</li>
<li>싱글톤 패턴을 통해 데이터 동기화 문제를 해결하고 정합성을 지키고자 했다.</li>
<li>클린코드를 지향하면서 인덱스명을 비롯한 사소한 변수들의 이름도 허투루 작성하지 않았다.</li>
</ul>
<h2 id="p---problem">P - Problem</h2>
<ul>
<li><p>시간 부족으로 장바구니와 같은 확장 기능으로 열어두었던 기능을 구현하지 못했다.</p>
</li>
<li><p>테스트 코드를 작성하지 못하고 Main에서 직접 기능을 사용하면서 테스트를 진행했다.</p>
</li>
<li><p>인터페이스를 작성하지 않고 바로 구현 클래스를 작성했다.</p>
</li>
<li><p>Main 클래스에 MVC 패턴을 적용하지 않아서 컨트롤러와 뷰 중 어떤 것이 진입점인지 판단하기 힘들었다.</p>
<ul>
<li>Main 클래스를 제외하고 다른 도메인에서는 모두 컨트롤러가 뷰와     모델을 연결해서 넘겨준다. 하지만 정작 제일 처음 진입하는 부분인 Main으로 생각하면 초기 화면을 print 해서 보여주기 때문에 뷰가 진입점이 아닐까 생각했다.</li>
<li>그런데 만약 Main 클래스에 MVC 패턴을 적용했다면?
컨트롤러가 뷰를 호출하기 때문에 컨트롤러가 진입점이 되지 않았을까 생각...!
=&gt; 따라서 진입점은 컨트롤러라는 결론</li>
</ul>
</li>
<li><p>컨트롤러에서 다른 도메인의 여러 서비스에 접근하면서 컨트롤러에 로직이 생성되었다.</p>
</li>
</ul>
<h2 id="t---try">T - Try</h2>
<ul>
<li>다음 프로젝트에서는 꼭 테스트 코드를 작성해야겠다.</li>
<li>인터페이스를 설계해서 확장성을 더 가져가고 싶다.</li>
<li>Main을 컨트롤러와 뷰로 나누어서 진입점을 명확히 하고 싶다.</li>
<li>서비스단에서 다른 도메인의 DAO에 접근하여 컨트롤러의 로직을 삭제하고 싶다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TDD란 좋은걸까?]]></title>
            <link>https://velog.io/@jina__/TDD</link>
            <guid>https://velog.io/@jina__/TDD</guid>
            <pubDate>Fri, 12 Jul 2024 16:09:50 GMT</pubDate>
            <description><![CDATA[<h2 id="tdd">TDD?</h2>
<p>Test-Driven Development. 줄여서 TDD.
말 그대로 테스트가 개발의 주체가 되는 개발 방법으로, 테스트를 먼저 작성하고 그 테스트를 통과하는 코드를 나중에 작성하는 방법론이다.</p>
<p>한때 배달의 민족의 어떤 팀에서 TDD를 강조한다는 사실이 알려져서 TDD가 엄청난 이슈로 떠오르기도 했었다.</p>
<h3 id="tdd의-개발-주기">TDD의 개발 주기</h3>
<p>그렇다면 TDD의 개발은 어떤 식으로 진행될까?
<img src="https://velog.velcdn.com/images/jina__/post/314180ca-6f80-459d-8300-bf496f89629d/image.png" alt=""></p>
<p>🟥실패하는 테스트 코드를 먼저 작성한다.
🟩테스크 코드를 성공시키기 위한 실제 코드를 작성한다.
🟦중복 코드 제거, 일반화를 통한 리팩토링을 수행한다.</p>
<p>큰 틀은 다음과 같이 진행된다.
이때 중요한 것은 실패하는 테스트 코드를 작성할 때까지는 실제 코드를 작성하지 않아야 되고, 실패하는 테스트를 통과할 정도의 최소 실제 코드를 작성해야 한다.</p>
<h3 id="그렇다면-tdd는-좋은걸까">그렇다면 TDD는 좋은걸까?</h3>
<p>분명 장점이 있으니까 쓰는 사람이 생겼고, 하나의 유행처럼 번지지 않았을까 생각한다.
일단 TDD의 장점은</p>
<blockquote>
<ol>
<li>완성도 높은 설계
 TDD는 테스트 코드를 먼저 작성하기 때문에 무엇을 해야하는지 분명히 정의하고 개발을 시작하게 된다. 또한 테스트를 작성하면서 다양한 예외상황에 대해 생각해 볼 수 있으므로 완성도 높은 설계를 하게 된다.</li>
</ol>
<ol start="2">
<li>튼튼한 객체지향적인 코드
 TDD는 코드의 재사용성을 보장할 것을 명시하므로 철저한 모듈화가 이루어진다. 따라서 종속성과 의존성이 낮은 모듈로 조합된 소프트웨어 개발이 가능하며, 필요에 따라 모듈을 추가하거나 제거해도 소프트웨어 전체 구조에 영향을 미치지 않는다.</li>
</ol>
<ol start="3">
<li>디버깅 시간 단축
 TDD에서는 유닛 테스트를 진행한다. 따라서 버그가 발생한다면 어디에서 발생하는 버그인지 바로 알아차릴 수 있다.</li>
</ol>
<ol start="4">
<li>테스트 문서 대체 가능
 보통 작성하는 테스트 정의서는 단순 통합테스트 문서에 지나지 않는다. 즉, 내부의 로직들이 어떻게 테스트 되는지 알 수 없다는 소리다. 하지만 TDD를 하게 될 경우 테스팅을 자동화 시킴과 동시에 보다 정확한 테스트 근거를 산출할 수 있다.</li>
</ol>
<ol start="5">
<li>추가 구현의 용이함
 개발이 완료된 소프트웨어에 어떤 기능을 추가할 때 가장 우려되는 점은 해당 기능이 기존 코드들에 어떤 영향을 미칠지 모른다는 점이다. 따라서 단순한 기능이라도 추가 된 후에는 모든 기능들을 처음부터 테스트 해야한다. 하지만 TDD의 경우 자동화된 유닛 테스팅을 전재하므로 이러한 테스트 기간 역시 획기적으로 단축시킬 수 있다.</li>
</ol>
</blockquote>
<p>TDD는 이렇게 좋은 장점들을 가지고 있다.
하지만 TDD를 따르지 않는 사람들도 분명 많다. 왜 그럴까?</p>
<h3 id="tdd의-단점">TDD의 단점</h3>
<blockquote>
<ol>
<li>생산성 저하
 TDD 방식의 개발 시간은 일반적인 개발 방식에 비해 대략 10~30% 정도로 늘어난다. 처음부터 2개의 코드를 짜야하고, 중간중간 테스트를 하면서 고쳐나가야 하기 때문이다.</li>
</ol>
<p>2.학습의 어려움
    기존 방식으로 개발을 하던 사람들은 TDD를 익히기 어렵다.</p>
<ol start="3">
<li>테스트 코드에 매몰된다.
 개발을 잘하기 위해 TDD를 하는 것인데, TDD에 미숙하다면 테스트코드를 통과하는 코드를 짜는 것에만 집중하게 된다.</li>
</ol>
</blockquote>
<h3 id="그렇다면-나의-의견은">그렇다면 나의 의견은?</h3>
<p>사실 나는 잘 모르겠다. TDD에 대한 찬성, 반대 의견을 내세울만큼 TDD를 잘 알지 못한다. 
그럼에도 굳이 입장을 정한다면, 찬성쪽에 서고 싶다.</p>
<p>테스트 코드를 먼저 작성한다면
시니어 입장에서는 주니어 개발자를 리드하기에 편할테고,
주니어 입장에서는 테스트 코드를 따라 개발하면 되니까 개발하기 좀 수월할 테니까?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[나의 주력 언어란 뭘까]]></title>
            <link>https://velog.io/@jina__/%EB%82%98%EC%9D%98-%EC%A3%BC%EB%A0%A5-%EC%96%B8%EC%96%B4%EB%9E%80-%EB%AD%98%EA%B9%8C</link>
            <guid>https://velog.io/@jina__/%EB%82%98%EC%9D%98-%EC%A3%BC%EB%A0%A5-%EC%96%B8%EC%96%B4%EB%9E%80-%EB%AD%98%EA%B9%8C</guid>
            <pubDate>Wed, 10 Jul 2024 14:25:33 GMT</pubDate>
            <description><![CDATA[<h2 id="주력-언어가-무엇인가요">&quot;주력 언어가 무엇인가요?&quot;</h2>
<p>이런 질문을 받으면 나는 항상 난감했다. 주력 언어가 없기 때문이다.
이게 무슨 소리냐고 할 수 있는데, 일단 나는 프로젝트용 언어와 코딩테스트용 언어가 다르다.</p>
<p>프로젝트용 언어는 주로 자바스크립트를 써왔고, 코딩테스트용 언어로는 C++을 사용한다.</p>
<h3 id="대체-왜">대체 왜...?</h3>
<p>내가 대학교에 입학하고 제일 처음 접한 언어가 C++이다.
물론 이것이 코딩테스트용 언어로 C++을 선택한 이유가 되지는 못한다.</p>
<p>일단 나는 처음에는 객체지향 개념을 이해하지 못하고, 따라서 자연스럽게 C++을 싫어하게 되어서 C++을 멀리한 시간도 꽤 길다.</p>
<p>그렇게 C++와 내외하던 중 개발 동아리에 프론트엔드 직군으로 들어가게 되었고, 자연스럽게 자바스크립트로 프로젝트를 하기 시작했다.</p>
<h3 id="그렇다면-자바스크립트가-주언어-아닌가요">그렇다면 자바스크립트가 주언어 아닌가요?</h3>
<p>이 부분에 대해서는 당당하게 <strong>절대 그럴 수 없다</strong>고 말할 수 있을 것 같다.</p>
<p>일단 나는 적어도 주언어라고 당당하게 말할 수 있으려면, 해당 언어를 적어도 어느정도 이해하고, 프레임워크 없이 개발이 가능해야 한다고 생각한다.</p>
<p>하지만 나는 바닐라 자바스크립트를 잘 이해하지 못한 채로 리액트로 넘어갔고, 그 이후에도 자바스크립트를 이해하지 못했다...</p>
<p>리액트를 익힌 뒤로는 너무나도 당연히 리액트로 프로젝트를 진행했고, 그러다보니 순수 자바스크립트를 이해할 기회는 더더욱 없었다.
<del>이해하고 싶었지만 이해하지 못한 건지, 이해하고 싶지 않았던 건지는 잘 모르겠다</del></p>
<h3 id="프론트엔드-개발-때문에-자바스크립트-사용한-건-알겠고-코테-언어는-왜-c">프론트엔드 개발 때문에 자바스크립트 사용한 건 알겠고, 코테 언어는 왜 C++?</h3>
<p>이러한 상황에서 알고리즘 공부를 위한 언어를 하나 정해야 했다.</p>
<p>앞서 언급한 C++과 자바스크립트, 그리고 많은 사람들이 추천하는 파이썬... 
많은 선택지가 있었는데, 그 중 내가 선택한 것은 파이썬이었다.</p>
<p>C++과 자바스크립트는 써보기만 했지 잘 모른다는 것이 그 이유였고, 많은 사람들이 파이썬을 추천하는 데에는 분명 이유가 있을 것이라고 생각했다.</p>
<p>그렇게 파이썬으로 코딩테스트 공부를 시작했다. 
유명한 이코테 책을 사서 보기도 했고, 강의도 들었고... 당연히 백준 문제도 풀었다.</p>
<h3 id="그렇다면-파이썬아닌가요">그렇다면 파이썬...아닌가요?</h3>
<p>아니다.
파이썬으로 코테 공부를 시작한 것은 맞지만 이내 벽에 부딪혔다.</p>
<blockquote>
<ol>
<li>라이브러리를 import 하기 위해서는 이걸 암기해야 하는데, 뭐가 어떤 라이브러리에 있는지 외우는 것이 생각보다 만만치 않았다.</li>
<li>언어만 파이썬일 뿐 C++처럼 코드를 작성하고 있는 내 자신과 마주쳤다.</li>
</ol>
</blockquote>
<p>파이썬은 편의를 위한 라이브러리가 정말 많다.</p>
<p>물론 이것은 분명 장점이지만, 많이 제공된다는 것은 그만큼 어떤 기능이 어떤 라이브러리에 있는지 외워야 한다는 것을 의미한다.
그리고 파이썬은 이 많은 기능이 한 군데 모여있지 않았다.
단순 암기에 취약한 나는 이것이 큰 단점으로 와닿았다.</p>
<p>물론 암기 문제만 있었다면, 시간이 해결해줄 문제라고 생각할 수도 있었다.
문제를 풀다보면 자연스럽게 외우게 될 테니까?
<br/></p>
<p>하지만, 두 번째 문제에 마주쳤을 때는 파이썬이라는 언어를 사용하는 것이 맞는지 진지하게 고민하게 됐다.</p>
<p>분명 C++을 잘 모른다고 생각했는데, 그래도 학교 공부는 열심히 한 탓인지 나는 생각보다 C++ 문법에 익숙해져 있었다.
<del>참고로 우리 학과는 4년 내내 C++만 사용한다.</del></p>
<p>그리고 C++처럼 코딩하는 것이 너무 익숙해져 있던 건지, 파이썬이라는 언어로 코딩하면서 반복문을 돌릴 때 인덱스로 접근하고... 이런 일이 비일비재했다.</p>
<p>오히려 나에게 불편한 언어인 파이썬으로 코딩하면서 로직은 C++처럼 작성하는 일은...시간만 배로 드는 일이었다.
<del>나중에 알았는데, C언어 사용자가 파이썬으로 넘어올 때 흔히 겪는 문제라고 한다.</del></p>
<p>그렇게 파이썬이라는 언어가 나에게는 불편한 언어일 수도 있겠다는 것과, 생각보다 내가 C++에 익숙해져 있다는 것을 깨닫고 C++으로의 언어 변경을 고민하던 중...</p>
<h3 id="삼성sds-알고리즘-특강에-c분반으로-입과하다">삼성SDS 알고리즘 특강에 C++분반으로 입과하다.</h3>
<p><img src="https://velog.velcdn.com/images/jina__/post/2f4c8a87-62e0-4d70-9e55-f2c7eb8d0c28/image.png" alt=""></p>
<p>갑자기요?
라고 물어본다면 정말 갑자기가 맞다...^_^</p>
<p>당시 알고리즘 공부를 하고 싶어서 특강 신청을 했었는데, 언어 선택지가 자바와 C++밖에 없어서 당연히 C++로 신청했다가, 진짜 뽑혔다...
<img src="https://velog.velcdn.com/images/jina__/post/fe3e3adb-0d9f-4580-9813-ddb357c843ef/image.png" alt=""></p>
<p>어쨌든 2주 동안 나는 꼼짝없이 C++로 알고리즘 문제를 풀어야 했고, 그 과정에서 생각지도 못한 C++의 장점을 알게 된다.</p>
<blockquote>
<ol>
<li>적어도 나에게는 문법 및 디버깅이 상당히 익숙하다.</li>
<li>당시 어렵게 느껴졌던 객체지향 개념은 알고리즘을 풀 때에는 필요가 없다.</li>
<li>어려운 문법인 포인터와 동적할당...이런 것도 필요가 없다.</li>
<li>생각보다 유용한 STL이 많다. 특히 &#39;vector&#39;와 &#39;algorithm&#39;만 있다면 우리는 무적 (이게 3의 이유가 되기도 한다.)</li>
<li>4와 이어지는 내용인데, 유용한 STL이 많은 반면, 파이썬처럼 외우기는 힘들지 않다. 대부분의 기능이 &#39;algorithm&#39;에 있기 때문...!</li>
<li>시간 측면에서 상당히 빠르다.</li>
</ol>
</blockquote>
<p>그렇게 나는 2주의 특강을 통해 코테 언어를 정하게 되고, 이후 코딩테스트 모두 C++으로 응시하게 된다.</p>
<h2 id="그런데눈에-들어오는-다른-언어가-생겨버렸다">그런데...눈에 들어오는 다른 언어가 생겨버렸다...!</h2>
<h3 id="자바">&quot;자바&quot;</h3>
<p>요즘 새로 공부하고 있는 언어이다.</p>
<p>프로젝트를 할 때 백엔드 개발자와 협업하는 과정에서 백엔드에 관심이 생겼고, 자바는 C++과 비슷하다는 말을 익히 들어서 전부터 공부하고 싶다는 생각은 계속 했었는데, 눈 앞에 닥친 일들이 너무 급해서 계속 미뤄두고만 있었다...</p>
<p>그런데 좋은 기회를 통해 백엔드 수업을 듣게 되었고, 수업을 들으면서 동시에 김영한님의 자바와 스프링 강의를 들으면서 자바와 친해지고 있는 중이다.</p>
<p>내 생각보다 자바는 더 C++과 비슷한 언어이고, C++보다 더 객체지향에 미친 놈이라는...생각이 들었다.</p>
<p>그리고 <strong>객체지향...</strong>
예전 같았으면, 여기에서 포기를 했겠지만, 4년만에 다시 만난 객체지향은 생각보다 괜찮았다.
두번째여서 그런가 그럭저럭 잘 이해되고, 흥미까지 생기는... 신기한 경험을 했다.</p>
<p>그리고 자바 공부를 하면서 느끼는 것은, 내가 정처기를 공부하면서 봤던 대부분의 것들이 백엔드에서 직접 쓰이는 개념이라는 것이었다.</p>
<p>SOLID 원칙과 MVC 패턴 등등...프론트엔드 프로젝트 경험만 갖고 있을 때는 이게 도대체 무슨 뜬구름 잡는 소리인가 싶었는데, &#39;이게 이거였구나&#39;를 직접 가슴으로 느끼는 중이다.</p>
<h3 id="그렇다면-c과-비교한-자바의-특징은">그렇다면 C++과 비교한 자바의 특징은?</h3>
<p>여기서 그럼, 자바와 C++의 차이점을 한 번 짚고 넘어갈 필요가 있을 것 같다.
<del>자바스크립트와의 비교는 의미가 없을 것 같다. 아마 이름만 비슷하고 모든 게 다르지 않을까...</del></p>
<blockquote>
<ol>
<li>범용성이 좋다.</li>
<li>C++의 단점을 상당히 개선해냈다.</li>
<li>C++보다 객체지향에 더 진심이다.</li>
</ol>
</blockquote>
<p>먼저 <strong>첫 번째</strong>,</p>
<p>많은 사람들이 알고 있듯이 자바는 백엔드 개발에 쓰이는 대표적인 언어이다. 그만큼 개발을 더 편리하게 할 수 있도록 도와주는 스프링이라는 프레임워크도 존재한다.</p>
<p>하지만 C++은...? 그런 거 없다ㅎㅎㅎ</p>
<p>아마 C++이 특화된 분야인 임베디드에 있어서는 자바보다 더 강점을 가질지도 모르지만, 적어도 내가 공부하는 웹 개발 분야에서는 C++과 비교한다는 것이 자바에게 미안할 정도이다.
<del>C++으로 프로젝트를 한다는 말조차 들어본 적이 전무하다.</del>
<BR/></p>
<p>그리고 <strong>두 번째</strong>,
자바는 C++의 단점을 다음과 같이 개선해냈다.</p>
<ul>
<li>GC를 통한 메모리 누수 문제 해결</li>
<li>운영체제에 종속적인 C++에 비해 운영체제에 독립적</li>
<li>문법 쉬워짐</li>
</ul>
<p>먼저 메모리 누수...
매번 할당 해제를 안한다거나 소멸자를 호출하지 않는다는가...이런 문제로 메모리 누수를 일으켰던 나 같은 사람을 위해서 <strong>Garbage Collector</strong> (GC)가 등장했다.</p>
<p>그리고 운영체제에 종속적으로 작동하는 C++과 달리, 자바는 JVM이라는 가상 머신을 통해서 독립적으로 작동할 수 있다는 장점을 갖고 있다.</p>
<p>또한, 자바는 C++에 비해 문법이 상당히 쉬워졌다. 일단 포인터 같은 개념이 등장하지 않는다.
물론 이런 개념은 분명 알아야 하는 개념인 만큼, CS 공부를 하기에는 C/C++만한 언어가 없다고 생각한다.
하지만 그래도 어려운 개념인 것 만큼은 분명해서, 안쓰고 개발할 수 있다면 좋지 않을까...?
그런 면에서 자바는 정말 훌륭한 언어이다.
<BR/></p>
<p>마지막 <strong>세 번째</strong>,
어쩌다보니 자바의 장점만 나열했는데, 순수하게 차이점을 언급하자면, 
앞서 언급했듯이 자바는 C++보다 <strong>객체지향에 더 미친 놈...</strong>이다.</p>
<ul>
<li>C++에서는 STL이라는 용어를 사용하는데, 자바에서는 Collection API라는 말을 사용한다.</li>
<li>자바에는 C++에는 없는 인터페이스가 있다.</li>
</ul>
<p>C++에서 사용하는 STL은 말 그대로 &#39;라이브러리&#39;라는 뜻으로, &#39;템플릿을 활용한 자료구조와 알고리즘의 모음&#39;을 뜻한다.
그런데 자바에서 사용하는 Collection API는 &#39;객체 지향 특성에 맞춘 자료구조 인터페이스와 클래스의 모음&#39;이라는 뜻이다.</p>
<p>여기에서 두 언어의 철학적인 면을 엿볼 수 있는데, C++은 템플릿을 통한 일반화 및 성능 최적화를 강조하고, 자바는 객체 지향 원칙을 강조함을 알 수 있다.
<br/></p>
<p>그리고 자바에는 C++에는 없는 인터페이스가 있다.
인터페이스란, 다른 클래스를 작성할 경우에 기본이 되는 틀을 제공하면서 다른 클래스 사이의 중간 매개 역할까지 담당하는 일종의 추상클래스이다.
즉, 클래스를 작성하기 위한 &#39;규약&#39;이라고 볼 수 있다.</p>
<p>그런데 C++에는 이 인터페이스 개념이 없다.
그저 추상 클래스만 있을 뿐...</p>
<p>여기에서 자바가 C++보다 클래스, 객체지향 이런 개념에 더 진심이라고 볼 수 있다.</p>
<h3 id="그래서-자바는">그래서 자바는?</h3>
<p>내 기준 정말 좋은 언어이다.</p>
<p>자바 덕분에 객체지향 개념과도 많이 친해졌다.
그래서 더 친해지고 싶고, 계속 공부해서 다음 프로젝트에서는 백엔드 개발자로서 참여해보려고 한다.</p>
<p><del>사실 빠르게 친해지고 싶어서 알고리즘 언어도 자바로 바꿀까 고민했으나, C++의 cin, cout 이라는 편리한 입출력과 import, 아니 include의 편리함을 포기할 수가 없어서 고민만...하는 중이다.</del></p>
<h3 id="결론">결론</h3>
<p>잊고 있을지도 모르지만, 이 글의 주제는 <strong>&#39;나의 주력 언어&#39;</strong>이다.
하지만 결론은 내릴 수가 없을 것 같다.</p>
<p>여전히 나는 주력 언어를 찾고 있는 중이고, 아래와 같은 물음표를 계속 나에게 던지고 있는 중이기 때문이다.</p>
<p><strong>&quot;나의 주력 언어란 뭘까?&quot;</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[많이 늦은...나의 첫 프로젝트 회고]]></title>
            <link>https://velog.io/@jina__/%EB%A7%8E%EC%9D%B4-%EB%8A%A6%EC%9D%80...%EB%82%98%EC%9D%98-%EC%B2%AB-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jina__/%EB%A7%8E%EC%9D%B4-%EB%8A%A6%EC%9D%80...%EB%82%98%EC%9D%98-%EC%B2%AB-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 09 Jul 2024 05:05:18 GMT</pubDate>
            <description><![CDATA[<h2 id="나의-첫-프로젝트">나의 첫 프로젝트</h2>
<p>약 2년 전쯤, 개발 동아리를 하면서 첫 프로젝트이자 첫 해커톤을 진행했다.</p>
<blockquote>
<p>[Personal] 지극히 개인적인, 나만의 감각을 찾아주는 Personal
<a href="https://github.com/wlsdk9803/personal-onlyFE">https://github.com/wlsdk9803/personal-onlyFE</a></p>
</blockquote>
<p>위 프로젝트인데, 많이 늦었지만 이 프로젝트에 대해 KPT 회고를 작성해보고자 한다. </p>
<h2 id="k---keep">K - Keep</h2>
<p>첫 프로젝트임에도 시간 내에 계획했던 기능을 모두 구현했다.
해커톤에서 기능을 모두 구현한다는 것은 생각보다 큰 강점이었고, 이것을 통해 4개 팀 중 1위를 할 수 있었다.</p>
<p>하지만 기능만 구현했을 뿐, 심각한 문제가 있었는데...</p>
<h2 id="p---problem">P - Problem</h2>
<p>바로 부족한 실력에 시간에 쫓기다보니 코드의 가독성이나 효율성 따위는 전혀 고려하지 못하고 오로지 구현 그 자체에 집중하게 된 것이다.
당시에도 같은 코드를 계속 ctrl C + ctrl V 하고 있는 그 상황이 뭔가 잘못되었다는 것은 감지했었는데, 어디서부터 어떻게 손봐야 할지 모르겠어서 그대로 두었다...</p>
<p>그리고 이 부분은 두고두고 아쉬운 점으로 자리잡게 되었고, 이후 프로젝트를 할 때에는 같은 실수를 하지 않겠다고 결심했다.</p>
<h3 id="실수의-반복">실수의 반복?</h3>
<p>하지만, 프로젝트는 나 혼자 하는 것이 아니다. 아무리 내가 코드의 중복을 없애고 컴포넌트의 재사용성을 높여야겠다고 다짐해도, 팀원들과 원만한 소통이 되지 않으면 서로 같은 기능을 하는 컴포넌트를 각자 만들고 있는 대참사가...발생한다.</p>
<p>이번 주토피아 프로젝트를 진행하면서도 그런 일이 발생했다. 나를 포함한 팀원 3명이 담당한 부분에서 공통 컴포넌트가 존재했다. 그래서 나는 다른 팀원들이 만들어놓은 컴포넌트를 재사용하려고 했는데, 두 팀원들이 만들어놓은 컴포넌트가 분명 같은 기능을 하는 것임에도 로직이 완전히 달라서 이해하는 데에 시간이 필요했다. 심지어 두 코드 모두 재사용성은 고려하지 않고 작성되어 있어서, 두 코드를 재사용성까지 고려해서 합치는 것보다 차라리 새로 만드는 게 훨씬 빠를 것 같다는 느낌을 받았다...</p>
<h3 id="그래도-리팩토링-해보자">그래도 리팩토링 해보자</h3>
<p>하지만 이미 이전 프로젝트에서 그렇게 흐린 눈을 하고 아쉬움이 남았던터라, 이번에도 그렇게 하면 평생 구현에만 목메고 나중에 후회할 것만 같았다.
그래서 결국 두 코드를 리팩토링 하기로 결심하고, 이틀 내내 해당 컴포넌트를 리팩토링 하는 데에만 시간을 썼다,,</p>
<p>근데 확실히 리팩토링 하고 나니까 가독성도 올라가고, 이후 개발 속도도 더 빨라지는 느낌을 받았다.</p>
<h3 id="그렇다면-personal도">그렇다면, Personal도?</h3>
<p>그래서 추후 기회가 된다면 처음 만들었던 Personal 프로젝트를 리팩토링 하고 싶다는 생각이 들었다.</p>
<p>일단...프로젝트 코드를 살펴보면 폴더 구조부터 엉망이다.</p>
<p><img src="https://velog.velcdn.com/images/jina__/post/bc03d50a-7fb2-4bc4-9612-b6608b0c931e/image.png" alt=""></p>
<p>ColorQ1, ColorQ2, ... 이런 것들이 거슬린다면 그게 맞다.
해당 컴포넌트들은 모두 같은 컴포넌트다...^_^
심지어는 ColorQ1과 MusicQ1도 하나로 통일할 수 있다...ㅋ...</p>
<p>또 저 MusicResult 폴더를 들어가보면
<img src="https://velog.velcdn.com/images/jina__/post/0bb43707-5cd1-4417-bf61-2f91274f7d1e/image.png" alt="">
이런 식으로 결과마다 컴포넌트가 따로 따로 만들어져 있다...^_^</p>
<p>당시 결과를 백엔드에서 불러올까 프론트엔드에서 처리할까 고민하다가 프론트엔드에서 처리하기로 했는데, 아무것도 몰랐던 나는 그게 저렇게 컴포넌트를 따로 만들라는 건줄 알았다.</p>
<p>근데 이제 와서 생각해보면 결과 데이터는 json 형태로 저장하고, 컴포넌트는 하나만 만들어서 결과마다 json 파일에서 필요한 부분만 불러오면 되는 거였다.</p>
<p>그리고 또 마음에 안드는 부분이 있는데
<img src="https://velog.velcdn.com/images/jina__/post/d6247063-6813-4ed1-ac12-16312664f88f/image.png" alt="">
여기 보면 Result 컴포넌트가 왜 저렇게 되어있는지 모르겠다...^_^</p>
<p>아마 저걸 만들 당시에는 나름대로 컴포넌트를 분리한다고 한 것 같은데, 오히려 가독성만 해치는 의미없는 분리가 되어버렸다.</p>
<p>심지어 모달은 왜 또 저렇게 되어있는지 아시는 분...? 허허</p>
<h2 id="t---try">T - Try</h2>
<p>정말 말 그대로 &#39;총체적 난국&#39;인 프로젝트이지만,
당시에는 첫 프로젝트 치고 꽤 완성도가 있는 프로젝트라고 생각했고, 상당히 뿌듯했던 프로젝트였다.
그래서 사실 건드리기가 너무 두렵고 새로 만드는 게 훨씬 빠를 것 같은 프로젝트이지만, 그래도 이걸 리팩토링해보고 싶어졌다.</p>
<p>언젠가 이걸 리팩토링 하게 된다면 후기를 남기러 와야겠다.
빠른 시일 내에 후기를 남길 수 있길...ㅎㅎ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTP의 Request와 Response]]></title>
            <link>https://velog.io/@jina__/HTTP%EC%9D%98-Request%EC%99%80-Response</link>
            <guid>https://velog.io/@jina__/HTTP%EC%9D%98-Request%EC%99%80-Response</guid>
            <pubDate>Sun, 07 Jul 2024 09:18:02 GMT</pubDate>
            <description><![CDATA[<p>웹 개발에 있어서 HTTP 얘기는 빼놓을 수 없다. 백엔드, 프론트엔드 개발자 모두에게 중요한 개념이고, 따라서 이걸 좀 정리해볼까 한다.</p>
<h3 id="http란-뭘까">HTTP란 뭘까?</h3>
<p>먼저, HTTP가 무엇인지부터 짚고 넘어가야겠다.</p>
<blockquote>
<p>HTTP란 &#39;Hypertext Transfer Protocol&#39;의 약자로, 쉽게 말해 Hypertext를 전송하기 위한 통신규약이다. 
이때 Hypertext는 직역하면 &#39;초월적인 텍스트&#39;가 나오는 만큼, 한 문서에서 다른 문서로 즉시 접근할 수 있는 텍스트를 의미한다. 
말이 어려운데, 쉽게 말해 하이퍼링크를 생각하면 된다.</p>
</blockquote>
<h3 id="http의-특징은">HTTP의 특징은?</h3>
<p>HTTP는 클라이언트와 서버 사이에 이루어지는 Request(요청)/Response(응답) 프로토콜이다. 클라이언트의 요청에 대해서만 응답이 존재하고, 응답까지 전송된 뒤에는 연결이 끊어진다. 이는 즉, 상태를 저장하지 않는다는 것을 의미한다. 요청들 사이에 연관성이 없고 독립적이라는 뜻이다.
따라서 상태를 저장해서 사용자와 일관된 상호작용 하기를 원한다면, 쿠키와 세션 등을 이용한다.</p>
<h3 id="요청과-응답">요청과 응답?</h3>
<p>앞서 언급했듯이 HTTP는 요청과 응답을 처리하는 프로토콜이다. 그렇다면 요청과 응답은 어떻게 구성되어 있을까?</p>
<h4 id="1-요청">1) 요청</h4>
<p>먼저 요청 부분, Request Message는 Blank line을 제외하고 총 3가지 부분으로 나누어진다.</p>
<ul>
<li>Request line</li>
<li>Header lines</li>
<li>Entity body
<img src="https://velog.velcdn.com/images/jina__/post/45a36740-4664-4875-b237-1b5c3d3802ae/image.png" alt=""></li>
</ul>
<br/>
전형적인 HTTP Request Message는 다음과 같다.

<pre><code>GET /somedir/page.html HTTP/1.1
Host: www.someschool.edu
Connection: close
User-agent: Mozilla/5.0
Accept-language: fr</code></pre><p>(1) Request line
Request line은 method 필드, URL 필드, HTTP 필드의 총 3개의 필드를 갖는다.</p>
<ul>
<li>method 필드: 요청의 의도를 담고 있다. GET, POST, HEAD, PUT, DELETE 등 여러 가지 값을 가진다.</li>
<li>URL 필드: Request가 전송되는 목표 주소를 담고 있다.</li>
<li>HTTP 필드: HTTP version을 담고 있다. 버전에 따라 메시지 구조나 데이터가 다를 수 있기 때문에 버전을 명시한다.</li>
</ul>
<p>(2) Header lines</p>
<pre><code>Host: google.com
Accept: text/html
Accept-Encoding: gzip, deflate
Connection: keep-alive
...</code></pre><p>해당 Request에 대한 추가 정보를 담고 있는 부분으로, Host, Accept, Accept-Encoding 등을 갖는다.</p>
<ul>
<li>Host: 요청하려는 서버 호스트 이름과 포트번호</li>
<li>User-agent: 클라이언트 프로그램 정보로, 이를 통해 서버는 클라이언트의 브라우저에 맞는 데이터를 보내줄 수 있다.</li>
<li>Referer: 바로 직전에 머물렀던 웹 링크 주소</li>
<li>Accept: 클라이언트가 처리 가능한 미디어 타입 종류</li>
<li>If-Modified-Since: 컨텐츠가 마지막으로 변경된 시점 정보. 페이지가 수정되었으면 최신 페이지로 교체한다.</li>
<li>Authorization: 인증 토큰을 서버로 보낼 때 필요한 정보</li>
<li>Origin: 서버로 Post 요청을 보낼 때 요청이 어느 주소에 시작되었는지 나타낸다. 이 값으로 요청을 보낸 주소와 받는 주소가 다르면 CORS 에러가 발생한다.</li>
<li>Cookie: 쿠키 값이 key-value 형태로 표현된다.</li>
</ul>
<p>(3) Entity body
Request가 전송하는 데이터를 담고 있는 부분으로, 전송하는 데이터가 없다면 비어있다.
보통 post 요청일 경우, 데이터가 들어있다.</p>
<pre><code>POST /test HTTP/1.1

Accept: application/json
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 83
Content-Type: application/json
Host: google.com
User-Agent: HTTPie/0.9.3

{
    &quot;test_id&quot;: &quot;tmp_1234567&quot;,
    &quot;order_id&quot;: &quot;8237352&quot;
}</code></pre><h4 id="2-응답">2) 응답</h4>
<p>응답 부분, Response Message도 Blank line을 제외하고 총 3가지 부분으로 나누어진다.</p>
<ul>
<li>Status line</li>
<li>Header lines</li>
<li>Entity body
<img src="https://velog.velcdn.com/images/jina__/post/4ac818a6-b217-4dff-8ce6-bda3f02abeb0/image.png" alt=""></li>
</ul>
<br/>
전형적인 HTTP Response Message는 다음과 같다.

<pre><code>HTTP/1.1 200 OK
Connection: close
Date: Tue, 18 Aug 2015 15:44:04 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 18 Aug 2015 15:11:03 GMT
Content-Length: 6821
Content-Type: text/html
(data data data data data ...)</code></pre><p>(1) Status line
Status line은 버전 필드와 상태 코드, 해당 상태 메시지를 갖는다.</p>
<ul>
<li>200 OK: 요청이 성공했고, 정보가 응답으로 보내졌다.</li>
<li>301 Moved Permanently: 요청 객체가 영원히 이동되었다. 이때, 새로운 URL은 응답 메시지의 Location 헤더에 나와있다</li>
<li>400 Bad Request : 서버가 요청을 이해할 수 없다.</li>
<li>404 Not Found : 요청한 문서가 서버에 존재하지 않는다.</li>
<li>505 HTTP Version Not Supported : 요청 HTTP 프로토콜 버전을 서버가 지원하지 않는다.</li>
</ul>
<p>(2) Header lines
Request의 headers와 대부분 동일하지만, response에서만 사용되는 header 값들이 있다.
대표적인 header 값은 다음과 같다.</p>
<ul>
<li>Connection : 클라이언트에게 메시지를 보낸 후 TCP 연결을 닫을지 말지 결정한다.</li>
<li>Date : HTTP 응답이 서버에 의해 생성되고 보낸 날짜와 시간을 나타낸다.</li>
<li>Server : 메시지가 어떤 웹 서버에 의해 만들어졌는지 나타낸다.</li>
<li>Last-Modified : 객체가 생성되거나 마지막으로 수정된 시간과 날짜를 나타낸다.</li>
<li>Content-Length : 송신되는 객체의 바이트 수를 나타낸다.</li>
<li>Content-Type : Entity body의 객체가 어떤 타입인지 나타낸다.</li>
</ul>
<p>(3) Entity body
Request의 body와 일반적으로 동일하다.
데이터를 전송할 필요가 없을 경우에는 비어있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[부모 클래스와 자식 클래스]]></title>
            <link>https://velog.io/@jina__/%EB%B6%80%EB%AA%A8-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%9E%90%EC%8B%9D-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@jina__/%EB%B6%80%EB%AA%A8-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%9E%90%EC%8B%9D-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Thu, 04 Jul 2024 05:42:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ol>
<li>상속 관계를 결정하는 클래스란 뭘까?</li>
<li>생성자도 상속되는 걸까?</li>
<li>아래 사진에서 A와 B 중 어떤 것이 부모클래스일까?
<img src="https://velog.velcdn.com/images/jina__/post/9650b2ea-aff6-4a13-b0f1-e10aface61bf/image.png" alt=""></li>
</ol>
</blockquote>
<p>객체지향프로그래밍에는 4가지 중요한 특징이 있다. 추상화, 상속, 다형성, 캡슐화인데 지금은 그 중 &#39;상속&#39;에 대해 얘기해보려고 한다.</p>
<h3 id="먼저-상속이란">먼저, 상속이란?</h3>
<p>상속은 기존 클래스에 기능을 추가하거나 재정의하여 새로운 클래스를 정의하는 것을 의미한다.
<br/></p>
<p>예를 들면,
&#39;아이폰&#39;과 &#39;갤럭시&#39;라는 휴대폰을 클래스로 구현한다고 생각해보자.
이 둘을 각각 구현하려고 하면 생각보다 겹치는 기능이 존재한다는 것을 알 수 있다.
그 이유는 두 클래스 모두 &#39;스마트폰&#39;이라는 공통 분모를 갖고 있기 때문이다.
그렇다면, &#39;스마트폰&#39; 클래스를 먼저 만들어놓고 이를 이용해서 &#39;아이폰&#39;과 &#39;갤럭시&#39; 클래스에서 다른 부분만 각각 구현하면 되지 않을까?
<br/></p>
<p>이런 생각을 객체 지향에 적용한 개념이 바로 &#39;상속&#39;이다.
그리고 이 예제에서 부모 클래스는 &#39;스마트폰&#39;, 자식 클래스는 &#39;아이폰&#39;과 &#39;갤럭시&#39;가 된다.</p>
<h3 id="그렇다면-상속관계는-누가-결정할까">그렇다면, 상속관계는 누가 결정할까?</h3>
<p>결론부터 말하자면, 자바에서 상속은 자식 클래스가 결정한다.
사실 부모 클래스는 자신의 클래스를 누가 상속받았는지의 여부도 알 방법이 없다.
부모 클래스는 그냥 평범한 클래스인데, 자식 클래스가 &#39;extends&#39;라는 키워드를 통해 부모를 선택한다.</p>
<pre><code class="language-java">// Phone 클래스(부모)
package phone;

public abstract class Phone {
    private boolean power;

    public abstract void printLogo();

    public void turnOn(){
        printLogo();
        power = true;
        System.out.println(&quot;휴대폰이 켜졌습니다.&quot;);
    }

    public void turnOff(){
        power = false;
        System.out.println(&quot;띠로리로&quot;);
    }
}

// Galaxy 클래스(자식)
package phone;

public class Galaxy extends Phone{
    @Override
    public void printLogo() {
        System.out.println(&quot;*** Samsung ***&quot;);
    }
}

// Iphone 클래스(자식)
package phone;

public class Iphone extends Phone{
    @Override
    public void printLogo() {
        System.out.println(&quot;@@@ Apple @@@&quot;);
    }
}</code></pre>
<p>위 코드에서 자식 클래스에서 &#39;extends&#39; 키워드를 통해 부모를 상속받는 것을 알 수 있다.
그리고 두 자식 클래스 모두 부모로부터 printLogo, turnOn, turnOff라는 메서드를 상속 받는다.</p>
<h3 id="그렇다면-생성자도-상속받을까">그렇다면, 생성자도 상속받을까?</h3>
<p>자식 클래스는 부모 클래스의 메서드를 상속받는다. 물론 위의 printLogo처럼 상속받고 재정의 할 수도 있지만, 그렇지 않으면 부모 클래스의 메서드를 그대로 사용할 수 있다.
그렇다면, 생성자는?</p>
<p>이것도 결론부터 얘기하자면, 생성자는 상속이 불가능하다. 물론 자식 클래스에서 인스턴스를 생성할 때, 부모 클래스의 기본 생성자를 자동으로 호출하긴 한다. 하지만, 매개변수를 갖는 부모 클래스의 생성자는 자동으로 호출되지 않는다. 따라서 호출하고 싶다면, 자식 생성자의 첫 줄에 super() 키워드를 추가해서 명시적으로 부모 생성자를 호출해야 한다.</p>
<p>이렇게 호출을 명시적으로 해야 한다는 것은, 상속받지 못한다는 것을 의미한다.</p>
<h3 id="마지막으로-a와-b-둘-중-자식-클래스는">마지막으로, A와 B 둘 중 자식 클래스는?</h3>
<p>위에서 언급한 대로, 자식 클래스는 부모 클래스를 확장해서 구현한다.
이 얘기는 즉, 더 넓은 것이 자식 클래스라는 것이고 위 사진에서는 더 넓은 B가 자식 클래스가 된다.</p>
<p><del>어쩌면 Phone보다 Iphone이 더 구체화 된 것이니까 A가 자식 아니냐고 생각할 수도 있지만, 적어도 나는 컴퓨터 언어로 접근했을 때 B인 것이 명확해서 B라고 생각한다.</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C/C++과 비교한 자바의 실행과정]]></title>
            <link>https://velog.io/@jina__/CC%EA%B3%BC-%EB%B9%84%EA%B5%90%ED%95%9C-%EC%9E%90%EB%B0%94%EC%9D%98-%EC%8B%A4%ED%96%89%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@jina__/CC%EA%B3%BC-%EB%B9%84%EA%B5%90%ED%95%9C-%EC%9E%90%EB%B0%94%EC%9D%98-%EC%8B%A4%ED%96%89%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Wed, 03 Jul 2024 04:53:08 GMT</pubDate>
            <description><![CDATA[<p>보통 프로그래밍 언어를 처음 배우면 C언어로 프로그래밍에 입문한다.
<del>요즘은 파이썬으로 입문하지만...라떼는 C/C++이다</del>
하지만 우리나라는 자바 공화국이고...특히 백엔드 개발을 시작하면 자바는 필수적이라서 자바는 무조건 알아야 한다.
그리고 이때 자바를 배우는 과정에서 자연스럽게 기존에 알았던 C언어와 비교를 하게 된다.
나 또한 이러했고, 따라서 이를 정리해보려고 한다.</p>
<h3 id="먼저-cc에서-소스코드가-실행되는-과정부터-알아보자">먼저, C/C++에서 소스코드가 실행되는 과정부터 알아보자.</h3>
<ol>
<li><p>전처리 (.c -&gt; .i)
&#39;#include&#39;, &#39;#define&#39;과 같이 &#39;#&#39;으로 시작하는 전처리기 구문을 처리한다.</p>
</li>
<li><p>컴파일 (.i -&gt; .s)
소스코드를 어셈블리어로 바꿔준다.</p>
</li>
<li><p>어셈블 (.s -&gt; .o)
어셈블러가 어셈블리어를 오브젝트 코드로 바꿔준다. 이 오브젝트 코드를 기계어라고 한다. 즉, 기계가 드디어 제대로 이해할 수 있다는 소리!</p>
</li>
<li><p>링크 (.o + .a(라이브러리 파일) -&gt; .exe 또는 .out)
링커가 여러가지 오브젝트 파일들과 라이브러리 파일들을 하나로 합쳐 묶어서 실행파일로 생성해준다.
<img src="https://velog.velcdn.com/images/jina__/post/beb2d0da-4ef4-405e-b57e-82ac60c6babc/image.png" alt=""></p>
</li>
</ol>
<p>그리고 이 모든 과정을 합해서 빌드라고 한다.</p>
<h3 id="그렇다면-자바에서는-빌드-과정이-어떻게-이루어질까">그렇다면 자바에서는 빌드 과정이 어떻게 이루어질까?</h3>
<ol>
<li><p>컴파일 (.java -&gt; .class)
자바 소스코드가 바이트코드로 변환된다.</p>
</li>
<li><p>클래스로더
바이트코드를 JVM으로 끌고 들어가는데, 여기에서 링크 과정이 이루어진다.</p>
</li>
<li><p>실행엔진
JVM에 올라온 바이트코드들을 명령어 단위로 하나씩 가져와서 실행한다. 이때 인터프리트와 컴파일 두가지 방식을 병행한다.</p>
<blockquote>
<p><strong>인터프리터</strong>: 바이트코드를 하나씩 읽어서 실행한다. 이때 하나씩 실행할 때는 빠르지만, 전체적인 속도는 느리다는 단점이 있어서 다음의 컴파일 과정이 도입된다.</p>
<p><strong>JIT 컴파일러</strong>: 인터프리터의 단점을 보완하기 위해 도입되었다. 바이트코드 전체를 컴파일해서 바이너리코드로 변경한다. 이때 변경된 바이너리코드가 기계어이다.  </p>
</blockquote>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jina__/post/05c7c898-eb56-4682-a8ac-5923139af472/image.png" alt=""></p>
<hr>
<h3 id="왜-이렇게-다를까">왜 이렇게 다를까?</h3>
<p>C언어는 운영체제에 종속받는 언어이다. 운영체제가 CPU에 맞는 언어로 변환시켜주기 때문이다.
그런데 자바는 JVM이라는 가상머신을 통해 운영체제에 종속받지 않고, 독립적으로 실행할 수 있다.
이 JVM 때문에 이런 차이가 생기지 않았을까 생각한다.</p>
<h4 id="과정을-정리해보자면">과정을 정리해보자면,</h4>
<p>두 언어 모두 컴파일 과정이 있는데, 해당 과정은 공통적으로 개발자가 작성한 소스코드를 전체적으로 다른 코드로 변환해주는 과정이다.
물론 C/C++은 그 결과물이 운영체제에 종속적인 어셈블리 코드고, 자바는 JVM이 이해할 수 있는 언어인 바이트코드이다.
그 이후, C/C++은 먼저 기계어로 바꾼 뒤 링크 과정을 수행하지만, 자바는 먼저 링크 과정을 수행하고 난 뒤 JVM에서 기계어인 바이너리코드로 변경된다. 
또한 C/C++은 순수하게 컴파일만 수행되는 언어라면, 자바는 JVM 내에서 컴파일과 인터프리트가 같이 수행되면서 하이브리드 언어가 되었다.</p>
]]></description>
        </item>
    </channel>
</rss>