<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>usadev.log</title>
        <link>https://velog.io/</link>
        <description>개발자와 유사한 개발자입니다</description>
        <lastBuildDate>Wed, 12 Jun 2024 13:00:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>usadev.log</title>
            <url>https://velog.velcdn.com/images/usa_dev/profile/48efa926-0eda-4330-976e-608f3b96ca9d/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. usadev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/usa_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[🐶 데이터베이스 격리수준]]></title>
            <link>https://velog.io/@usa_dev/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EA%B2%A9%EB%A6%AC%EC%88%98%EC%A4%80</link>
            <guid>https://velog.io/@usa_dev/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EA%B2%A9%EB%A6%AC%EC%88%98%EC%A4%80</guid>
            <pubDate>Wed, 12 Jun 2024 13:00:19 GMT</pubDate>
            <description><![CDATA[<h1 id="📌개요">📌개요</h1>
<p>데이터베이스의 트랜잭션 격리수준이란 동시에 여러 트랜잭션이 수행될 때, 트랜잭션 간의 간섭을 어떻게 제어할지를 정의하는 설정이다.</p>
<p>데이터 일관성을 유지하면서 동시에 다수의 트랜잭션을 효율적으로 처리하는 데 중요한 역할을 한다.</p>
<p>트랜잭션 격리 수준은 네 가지 주요 수준이 있다.</p>
<h2 id="📖serializable">📖Serializable</h2>
<p>가장 엄격한 격리 수준으로 이름 그대로 트랜잭션을 순차적으로 진행시킨다.</p>
<p>여러 트랜잭션이 동일한 레코드에 동시 접근할 수 없으므로, 어떠한 데이터 부정합 문제도 발생하지 않는다.</p>
<p>하지만 트랜잭션이 순차적으로 처리되어야 하므로 동시 처리 성능이 매우 떨어진다.</p>
<p>즉, 가장 안전하지만 가장 성능이 떨어지므로 극단적으로 안전한 작업이 필요한 경우에만 사용된다.</p>
<h2 id="📖repeatable-read">📖Repeatable Read</h2>
<p>Repeatable Read는 하나의 트랜잭션 내에서 동일한 쿼리를 반복 실행할 경우, 항상 동일한 결과가 반환되도록 보장하는 격리 수준이다.</p>
<p>즉, 트랜잭션이 시작된 후에 수행된 SELECT 문은 이후에 데이터를 변경하거나 추가하는 다른 트랜잭션의 영향을 받지 않는다. 이를 통해 Non-Repeatable Read(반복 읽기 불가능) 문제를 방지할 수 있다.</p>
<p>하지만 <strong>Phantom Read(팬텀 리드)</strong>는 여전히 발생할 수 있다.
예를 들어 첫 번째 SELECT에서 조건에 맞는 행이 5개였는데, 같은 트랜잭션 내에서 두 번째 SELECT를 수행할 때 다른 트랜잭션이 새로운 행을 INSERT하고 커밋하면, 6개의 결과가 반환되는 상황이 발생할 수 있다.</p>
<p>MySQL(InnoDB)의 경우, Repeatable Read 격리 수준에서도 <strong>갭 락(Gap Lock)</strong>을 통해 팬텀 리드를 방지하므로, 사실상 Serializable에 가까운 동작을 한다.</p>
<h2 id="📖read-committed">📖Read Committed</h2>
<p>Read Committed는 <strong>커밋된 데이터만 조회</strong> 할 수 있다. Read Committed는 Repeatable Read에서 발생하는 Phantom Read에 더해 Non-Repeatable Read(반복 읽기 불가능) 문제까지 발생한다.</p>
<p>예를 들어 사용자 A가 트랜잭션을 시작하여 어떤 데이터를 변경하였고, 아직 커밋은 하지 않은 상태라고 할 때, 테이블은 먼저 갱신되고 언두 로그로 변경 전의 데이터가 백업된다.</p>
<p>이때 사용자 B가 데이터를 조회하려고 하면 Read Committed에서는 커밋된 데이터만 조회할 수 있으므로, Repeatable Read와 마찬가지로 언두 로그에서 변경 전의 데이터를 찾아서 반환하게 된다.</p>
<p>최종적으로 사용자 A가 트랜잭션을 커밋하면 그때부터 다른 트랜잭션에서도 새롭게 변경된 값을 참조할 수 있게 된다.</p>
<p>Read Committed에서 반복 읽기를 수행하면 다른 트랜잭션의 커밋 여부에 따라 조회 결과가 달라질 수 있다. 이러한 데이터 부정합 문제를 Non-Repeatable Read(반복 읽기 불가능)라고 한다.</p>
<p>일반적으로는 크게 문제가 되지 않지만, 예를 들어 어떤 트랜잭션에서 오늘 입금된 총 합을 계산하고 있는 도중 다른 트랜잭션에서 계속해서 입금 내역을 커밋하는 상황이라면 Read Committed에서는 같은 트랜잭션 일지라도 조회할 때 마다 입금된 내역이 달라지므로 문제가 생길 수 있다.</p>
<h2 id="📖read-uncommitted">📖Read Uncommitted</h2>
<p>Read Uncommitted는 <strong>커밋하지 않는 데이터 조차도 접근</strong>할 수 있는 격리 수준이다.
즉, 다른 트랜잭션의 작업이 커밋 또는 롤백되지 않아도 즉시 보이게 된다.</p>
<p>예를 들어 사용자 A의 트랜잭션에서 INSERT를 통해 데이터를 추가했다고 가정하자.
아직 커밋 또는 롤백이 되지 않는 상태임에도 불구하고 READ Uncommitted는 변경된 데이터에 접근할 수 있다.</p>
<p>이 경우 사용자 B 트랜잭션에서 커밋되지 않은 사용자 A의 데이터를 읽었다가 사용자 A 트랜잭션에서 갑자기 해당 데이터를 지워버린다면 사용자 B 트랜잭션에서는 데이터를 계속 처리하고 있을텐데, 다시 데이터를 조회하니 결과가 존재하지 않는 상황이 생긴다.</p>
<p>이를 Dirty Read라고 하며, 정합성에 문제가 많은 격리 수준이다.</p>
<p>출처 : <a href="https://mangkyu.tistory.com/299">https://mangkyu.tistory.com/299</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐶 객체지향 개발 5대 원칙 SOLID 알아보자]]></title>
            <link>https://velog.io/@usa_dev/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EA%B0%9C%EB%B0%9C-5%EB%8C%80-%EC%9B%90%EC%B9%99-SOLID-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@usa_dev/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EA%B0%9C%EB%B0%9C-5%EB%8C%80-%EC%9B%90%EC%B9%99-SOLID-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Wed, 05 Jun 2024 00:00:57 GMT</pubDate>
            <description><![CDATA[<h1 id="📌-개요">📌 개요</h1>
<p>SOLID는 객체 지향 설계에서 중요한 5가지 원칙을 의미한다. 이 원칙은 클린 아키텍처의 저자 로버트 마틴이 제안했으며, 소프트웨어 개발에서 의존성을 관리하고, 유지보수와 확장성을 향상시키기 위해 사용된다. 개인적으로 SOLID 원칙을 공부하기 전과 후로 코드보는 시선이 많이 달라졌다고 느낀다. </p>
<h3 id="📖-단일-책임-원칙single-responsibility-principle-srp">📖 단일 책임 원칙(Single Responsibility Principle, SRP)</h3>
<p>하나의 클래스는 하나의 책임만 가져야 한다는 원칙이다. 클래스 뿐만 아니라 메소드에도 해당하는 것 같다. 
그런데 책임? 책임이 뭘까 책임이란 역할이다 하나의 클래스, 하나의 메소드마다 각각의 역할과 관심사를 응집력있게 만들어 이를 통해 클래스가 더욱 명확해지고, 재사용에 용이하게 만들라는 의미이다. </p>
<p>이를 왜 지켜야 할까? 그냥 한곳에다 다 몰아서 하면 안되나? 각각의 역할별로 클래스와 메소드를 만들면 괜히 코드양만 늘어나지 않나? 그렇지 않다 아래 예시를 보자.</p>
<pre><code class="language-java">public class 사람 {

    void 일하기() {
        System.out.println(&quot;코드를 타다닥 타다닥 치는중 ...&quot;);
    }

    void 효도하기() {
        System.out.println(&quot;부모님께 효도하는중 ...&quot;);
    }

    void 데이트하기() {
        System.out.println(&quot;여자친구랑 데이트 하는중 ...&quot;);
    }

}</code></pre>
<p>사람이라는 클래스는 <strong>코딩하기, 효도하기, 데이트하기</strong> 라는 액션을 할 수 있는 메소드들이 있다.</p>
<p>만약 <strong>회사, 엄마, 여자친구</strong> 라는 클래스들이 있다고 가정할 때 이 클래스들은 유사 개발자 클래스를 의존하게 될 것 이다. 여기서 회사 클래스에서는 효도하기와 데이트하기와 같은 기능은 필요도 없는데 사용할 수 있게 된다.</p>
<p>벌써 맛이 없다.</p>
<p>또, 사람 클래스를 수정할 때 마다 해당 클래스들이 영향을 받게 된다.</p>
<p>이를 개선하기 위해서는 역할별로 클래스를 만들고 메소드를 분리한다면 SRP를 실천할 수 있게된다.</p>
<h3 id="📖-개방-페쇄-원칙openclosed-principle-ocp">📖 개방-페쇄 원칙(Open/Closed Principle, OCP)</h3>
<p>클래스, 모듈, 함수 등은 확장에는 열려있지만 변경에는 닫혀있어야 한다는 원칙이다. 즉, 기존 코드를 변경하지 않고도 기능을 수정하거나 확장할 수 있는 구조를 의미한다.</p>
<p>그런데 어떻게 기존 코드를 변경을 안하고 확장할 수 있는걸까? 아래 예시를 보자</p>
<pre><code class="language-java">public class UserRepository {
    private final MysqlConnector connector;

    public UserRepository(mysqlConnector connector) {
        this.connector = connector;
    }

    public void save(User user) {
        connector.save(user);
    }
}</code></pre>
<p>별로 이상한 점이 없는 코드지만, 만약 DBMS를 MySQL에서 Oracle로 변경해야 한다면 어떨까?</p>
<p>UserRepository가 의존하고 있는 MysqlConnector부분을 OracleConnector를 만들어서 수정해야 할 것이다.
그런데 만약 시스템 전체에서 MysqlConnector를 의존하고 있는 코드를 변경해야 한다 생각하면 어질어질 하다.</p>
<p>이를 개선하기 위해선 <strong>인터페이스</strong>를 사용하여 <strong>DatabaseConnector</strong> 라는 추상적인 개념을 만들면 된다.</p>
<p>핵심은 UserRepository가 <strong>특정 db벤더의 의존하지 않게끔</strong> 하는것이다. 개선된 코드를 보자</p>
<pre><code class="language-java">// DB연결부와 save 메소드를 추상화 시킨 후 인터페이스를 구현한 구현체들
public interface DatabaseConnector {
    void save(User user);
}

public class MysqlConnector implements DatabaseConnector {
    @Override
    public void save(User user) {
        System.out.println(&quot;Saving user to MySQL database&quot;);
    }
}

public class OracleConnector implements DatabaseConnector {
    @Override
    public void save(User user) {
        System.out.println(&quot;Saving user to Oracle database&quot;);
    }
}</code></pre>
<pre><code class="language-java">// 구현체에 의존하지 않고 인터페이스에 의존함으로써 OCP를 지킨 코드
public class UserRepository {
    private final DatabaseConnector connector;

    public UserRepository(DatabaseConnector connector) {
        this.connector = connector;
    }

    public void saveUser(User user) {
        connector.save(user);
    }
}</code></pre>
<p>이제 Mysql이던 Oracle이던 Maria던 상관없이 DatabaseConnector만 구현한 구현체를 꽂아주기만 하면 UserRepository를 수정하지 않고도 기능을 확장하거나 수정할 수 있게되었다.</p>
<h3 id="📖-리스코프-치환-원칙liskov-substitution-principle-lsp">📖 리스코프 치환 원칙(Liskov Substitution Principle, LSP)</h3>
<p>리스코프 치환 원칙은 1988년 바바라 리스코프가 올바른 상속 관계의 특징을 정의하기 위해 발표한 것이다.
<strong>서브 타입은 언제나 기반 타입으로 교체</strong>할 수 있어야 한다는 것을 뜻한다.</p>
<p>교체할 수 있다는 것은 자식 클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행이 보장되어야 한다는 의미이다.</p>
<p>즉, 부모 클래스의 인스턴스를 사용하는 위치에 자식 클래스의 인스턴스를 대신 사용했을 때 코드가 원래 의도대로 작동해야 한다는 의미이다.</p>
<p>이러한 LSP 원칙을 잘 적용한 예시가 자바의 <strong>컬렉션 프레임워크</strong> 이다.</p>
<p>만일 변수에 LinkedList 자료형에 담아 사용하다, 중간에 전혀 다른 HashSet 자료형으로 바꿔도 <strong>add()</strong> 메서드 동작을 보장받기 위해서는 Collection 이라는 인터페이스 타입으로 변수를 선언하여 할당하면 된다.</p>
<p>왜냐하면 인터페이스 Collection의 추상 메서드를 각기 하위 자료형 클래스에서 implements하여 인터페이스 구현 규약을 잘 지키도록 잘 설계가 되어있기 때문이다.
<img src="https://velog.velcdn.com/images/usa_dev/post/792b0eb0-90ce-45aa-bf25-e4cdab870ed1/image.png" alt=""></p>
<pre><code class="language-java">void main() {
    // Collection 인터페이스 타입으로 변수 선언
    Collection data = new LinkedList();
    data = new HashSet(); // 중간에 전혀 다른 자료형 클래스를 할당해도 호환됨

    modify(data); // 메소드 실행
}

void modify(Collection data){
    data.add(1); // 인터페이스 구현 구조가 잘 잡혀있기 때문에 add 메소드 동작이 각기 자료형에 맞게 보장됨
}</code></pre>
<p>리스코프 치환 원칙을 어긴 쉬운 예시로는 다음과 같다.</p>
<pre><code class="language-java">// 부모 클래스
class 새 {
    public void 날다() {
        System.out.println(&quot;새가 날고 있다.&quot;);
    }
}

// 자식 클래스
class 참새 extends 새 {
    @Override
    public void 날다() {
        System.out.println(&quot;참새가 날고 있다.&quot;);
    }
}

// 자식 클래스
class 타조 extends 새 {

    @Override
    public void 날다() {
        throw new UnsupportedOperationException(&quot;타조는 날 수 없다.&quot;);
    }
}
</code></pre>
<p>새라는 부모 클래스에는 날다라는 메소드가 있는데 타조의 경우 새의 한 종류 이긴 하지만 날 수는 없다. 
이 처럼 상속관계에서의 모호한 관계가 발생한 경우 이를 적절히 해결해줘야 한다.
해법으로는 날다라는 <strong>기능</strong>을 인터페이스로 만들어 적절히 구현하게 만들어주면 된다.</p>
<pre><code class="language-java">// 부모 클래스
class 새 {
    // 공통된 속성 및 메서드 정의
}

interface 날수있는 {
    void fly();
}

// 자식 클래스
class 참새 extends 새 implements 날수있는 {
    @Override
    public void 날다() {
        System.out.println(&quot;참새가 날고 있다.&quot;);
    }
}

// 자식 클래스
class 타조 extends 새 {

}</code></pre>
<h3 id="📖-인터페이스-분리-원칙interface-segregation-principle-isp">📖 인터페이스 분리 원칙(Interface Segregation Principle, ISP)</h3>
<p>인터페이스 분리 원칙은 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다는 원칙이다.
그 이유는 범용 인터페이스의 경우 구현해야할 추상 메서드들이 많이 있기 때문에 내가 구현하고 싶지 않아도 구현해야만 하는 불상사가 일어나기 때문이다.</p>
<pre><code class="language-java">interface 작업자 {
    void 작업하다();
    void 식사하다();
}

class 사람작업자 implements 작업자 {
    public void 작업하다() {
        System.out.println(&quot;사람이 작업하고 있습니다&quot;);
    }

    public void 식사하다() {
        System.out.println(&quot;사람이 식사하고 있습니다&quot;);
    }
}

class 로봇작업자 implements 작업자 {
    public void 작업하다() {
        System.out.println(&quot;로봇이 작업하고 있습니다&quot;);
    }

    // 로봇은 먹을 필요가 없지만, 인터페이스 때문에 식사하다() 메서드를 구현해야 한다
    public void 식사하다() {
        throw new UnsupportedOperationException(&quot;로봇은 식사할 수 없습니다&quot;);
    }
}</code></pre>
<h3 id="📖-의존성-역전-원칙dependency-inversion-principle-dip">📖 의존성 역전 원칙(Dependency Inversion Principle, DIP)</h3>
<p>의존성 역전 원칙이란 고수준 개념은 저수준 개념을 의존해서는 안된다는 원칙이다. 그리고 추상화는 구체적인 사항에 의존해서는 안되며, 구체적인 사항이 추상화에 의존해야 한다는 의미이다.</p>
<p>그럼 여기서 고수준은 뭐고 저수준은 무엇일까?</p>
<p>고수준 : 애플리케이션의 정책을 정의하는 개념이다. 주로 비즈니스 로직을 포함한다.
저수준 : 고수준 개념을 지원하는 영역으로 구체적은 구현 세부 사항을 포함한다. 데이터 베이스 접근, 네트워크 통신 등의 세부적인 기능을 담당한다.</p>
<pre><code class="language-java">interface DataRepository {
    void save(Object data);
}

class FileDataRepository implements DataRepository {
    public void save(Object data) {
        // 파일 시스템에 데이터 저장
    }
}

class HighLevelModule {
    private DataRepository dataRepository;

    public HighLevelModule(DataRepository dataRepository) {
        this.dataRepository = dataRepository;
    }

    public void performAction(Object data) {
        dataRepository.save(data);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐶 인터페이스와 추상 클래스 차이]]></title>
            <link>https://velog.io/@usa_dev/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@usa_dev/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Wed, 01 May 2024 11:41:48 GMT</pubDate>
            <description><![CDATA[<h1 id="📌-개요">📌 개요</h1>
<p>인터페이스와 추상클래스는 객체 지향 프로그래밍의 다형성을 구현하는데 중요한 역할을 한다.
둘 다 인스턴스화 할 수 없으며, 상속을 통해 자식 클래스에서 구현하거나 확장해야 한다.</p>
<p>둘다 추상 메서드를 포함할 수 있으며, 이를 통해 공통의 기능을 정의하고 코드의 재사용성을 높일 수 있다. 하지만 둘 사이에는 몇 가지 중요한 차이점이 있다.</p>
<h2 id="📖인터페이스">📖인터페이스</h2>
<ul>
<li>인터페이스는 모든 메서드가 추상 메서드로 선언되어있다.</li>
<li>자바 8부터는 default 메서드와 static 메서드를 포함할 수 있게 되었다.</li>
<li>인터페이스는 다중 상속을 지원한다.</li>
</ul>
<pre><code class="language-java">interface MyInterface {
    void method1();
    default void method2() {
        // 기본 구현
    }
}</code></pre>
<ul>
<li>인터페이스를 사용하면 여러 클래스가 같은 인터페이스를 구현함으로써 다형성을 구현할 수 있다.</li>
<li>인터페이스는 특히 API를 설계할 때 유용하게 사용된다.</li>
<li>인터페이스는 구현 클래스가 반드시 구현해야 하는 메서드의 명세를 제공하며, 이를 통해 일관된 방식으로 객체를 사용할 수 있다.</li>
</ul>
<h2 id="📖추상-클래스">📖추상 클래스</h2>
<ul>
<li>추상 클래스는 하나 이상의 추상 메서드를 포함할 수 있으며, 일반 메서드나 <strong>변수(상태)</strong> 도 포함할 수 있다.</li>
<li>추상 클래스는 단일 상속만을 지원한다.</li>
</ul>
<pre><code class="language-java">abstract class MyAbstractClass {
    protected int exampleVar;

    // 생성자를 통해 초기화
    public MyAbstractClass(int initialValue) {
        this.exampleVar = initialValue;
    }

    abstract void abstractMethod();

    void concreteMethod() {
        System.out.println(&quot;The value of exampleVar is: &quot; + exampleVar);
    }
}</code></pre>
<ul>
<li>추상 클래스를 사용하여 공통의 코드를 추상 클래스에 구현함으로써 코드 중복을 줄일 수 있다.</li>
<li>필요한 부분만 자식 클래스에서 구현하게 할 수 있다.</li>
<li>추상 클래스는 변수(상태)를 상속 계층 내에서 공유하거나, 특정한 행위를 정의하는데 있어 더 유연하게 활용될 수 있다.</li>
<li>추상 클래스는 상속을 통한 기능의 확장을 목적으로 사용된다.</li>
<li>추상 클래스는 인스턴스화 할 수 없으며, 상속받는 자식 클래스에서 추상 메서드를 모두 구현해야 한다. 이를 통해 클래스 계층 구조를 명확하게 나타낼 수 있다.</li>
</ul>
<h1 id="📚주요-차이점">📚주요 차이점</h1>
<p>인터페이스와 추상 클래스의 가장 큰 차이점은 다중 상속과 변수(상태) 공유 여부이다.</p>
<p>인터페이스는 메서드의 구현을 포함하지 않기 때문에 다중 상속에서 발생할 수 있는 문제가 없지만, 추상 클래스는 구현 코드를 포함할 수 있어 다중 상속 시 충돌의 위험이 있다.</p>
<p>그리고 상태를 가질 수 없는 인터페이스와는 달리 추상 클래스는 상태를 보유할 수 있다.
이는 상속받는 서브 클래스들이 이 상태를 상속받아 사용할 수 있음을 의미하며, 공통의 데이터 구조를 갖는 클래스 계층을 설계 할 때 유용하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐶 쿠키는 무엇이며 어디에 저장되는걸까?]]></title>
            <link>https://velog.io/@usa_dev/%EC%BF%A0%ED%82%A4%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%96%B4%EB%94%94%EC%97%90-%EC%A0%80%EC%9E%A5%EB%90%98%EB%8A%94%EA%B1%B8%EA%B9%8C</link>
            <guid>https://velog.io/@usa_dev/%EC%BF%A0%ED%82%A4%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%96%B4%EB%94%94%EC%97%90-%EC%A0%80%EC%9E%A5%EB%90%98%EB%8A%94%EA%B1%B8%EA%B9%8C</guid>
            <pubDate>Mon, 29 Apr 2024 13:13:26 GMT</pubDate>
            <description><![CDATA[<h1 id="📌개요">📌개요</h1>
<p>HTTP는 인터넷 상에서 데이터를 주고 받기 위한 서버-클라리언트 프로토콜이다. HTTP는 비연결성(conntectionless), 무상태성(stateless) 이라는 특징을 가지고 있다. HTTP는 요청에 대한 응답을 처리 완료하게 되면, 연결을 끊어 버린다. </p>
<p>이러한 특징 때문에 로그인을 하더라도 다음 요청에서는 해당 클라이언트를 기억하지 못하므로 또 로그인을 해야하는 문제가 발생한다. 이러한 Stateful 한 경우를 위해 HTTP의 비연결성 및 무상태성을 보완하기 위해 쿠키가 사용된다.</p>
<p>쿠키는 웹 사이트를 방문할 때 사용자의 브라우저에 저장되는 작은 텍스트 파일 이다. 이 텍스트 파일에는 사이트를 사용하는 동안 사용자의 활동에 관한 정보가 들어 있어, 웹 서버가 사용자를 식별하거나 사용자의 선호 설정, 쇼핑몰 장바구니 등을 기억하는 데 이용된다.</p>
<h2 id="📖-쿠키-종류">📖 쿠키 종류</h2>
<ul>
<li><p>세션 쿠키 : 일반적으로 메모리에 저장되며, 브라우저가 닫히면 자동으로 삭제된다. 이 쿠키는 임시 정보를 저장하는 데 사용되며, 브라우저 세션이 종료되면 사라진다.</p>
</li>
<li><p>영구 쿠키 : 하드 디스크에 저장되어 브라우저를 종료하거나 컴퓨터를 껐다 켜도 계속 유지된다. 이 쿠키는 만료 날짜가 설정되어 있어, 지정된 시간이 지나면 자동으로 삭제된다.</p>
</li>
</ul>
<h2 id="📚-로그인-상태-유지방법">📚 로그인 상태 유지방법</h2>
<p>로그인 상태를 유지하는 방법은 주로 영구 쿠키를 사용한다. 사용자가 로그인 할 때, 서버는 로그인 정보와 함께 만료 기간이 설정된 영구 쿠키를 생성하여 사용자의 브라우저에 저장한다.</p>
<p>사용자가 브라우저를 닫았다가 다시 열 때, 쿠키는 서버로 전송되어 사용자를 식별하고 로그인 상태를 유지할 수 있도록 도와준다.</p>
<p>이러한 쿠키는 사용자 경험을 향상시키는 동시에 보안상의 위험을 수반할 수 있기 때문에, 웹 사이트는 쿠키를 안전하게 관리하고 보호하기 위한 여러 조취를 해야한다.</p>
<blockquote>
<p>쿠키에 Secure 및 HttpOnly 플래그를 설정하여 HTTPS 연결을 통해서만 쿠키를 전송하고, 자바스크립트의 접근을 차단할 수 있다.</p>
</blockquote>
<h2 id="📚-쿠키-생성-및-상호작용">📚 쿠키 생성 및 상호작용</h2>
<ul>
<li><p>클라이언트가 서버에게 페이지 정보를 요청</p>
</li>
<li><p>서버는 클라이언트에 대한 쿠키 생성 후, HTTP 응답 헤더에 쿠키를 포함하여 응답(HTTP response 헤더의 &#39;Set-Cookie&#39;)</p>
</li>
<li><p>사용자의 브라우저는 Set-Cookie 헤더를 받고 나서, 쿠키를 로컬 저장소(하드 디스크)에 저장한다. </p>
</li>
<li><p>클라이언트의 요청과 서버의 응답이 끝나면 HTTP의 비연결성으로 인해 연결 끊김</p>
</li>
<li><p>새로운 요청을 할 경우, 이전에 받은 쿠키값을 보관하고 있다가 HTTP 요청 헤더에 값을 포함하여 요청(HTTP request 헤더의 &#39;cookie&#39;)</p>
</li>
<li><p>서버는 쿠키값을 보고 이전에 요청을 보낸 클라이언트를 인식하여 상태를 기억하여 HTTP의 stateless한 성질을 보완</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐶 컨텍스트 스위칭이란?]]></title>
            <link>https://velog.io/@usa_dev/%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%8A%A4%EC%9C%84%EC%B9%AD%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@usa_dev/%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%8A%A4%EC%9C%84%EC%B9%AD%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Tue, 23 Apr 2024 12:32:28 GMT</pubDate>
            <description><![CDATA[<h1 id="📌개요">📌개요</h1>
<p>컨텍스트 스위칭은 운영체제가 여러 프로세스나 스레드 사이에서 CPU 사용 권한을 전환할 때 발생하는 과정이다. 컴퓨터가 멀티태스킹을 수행하면서 여러 작업을 동시에 처리할 수 있는 능력을 가질 수 있는 핵심 기능 중 하나이다.</p>
<h2 id="📖-컨텍스트-스위칭-과정">📖 컨텍스트 스위칭 과정</h2>
<h3 id="📚-1-현재-프로세스-저장">📚 1. 현재 프로세스 저장</h3>
<ul>
<li>현재 실행 중인 프로세스의 컨텍스트를 해당 프로세스의 PCB에 저장한다.</li>
<li>이 정보는 프로세스가 나중에 다시 실행될 때 정확회 중단된 지점부터 시작할 수 있도록 한다.<h3 id="📚-2-스케줄러의-결정">📚 2. 스케줄러의 결정</h3>
</li>
<li>스케줄러는 다음에 실행할 프로세스를 결정한다. 이 결정은 프로세스의 우선순위, 알고리즘, 시스템 정책 등에 기반한다.<h3 id="📚-3-새-프로세스의-pcb로부터-컨텍스트-불러오기">📚 3. 새 프로세스의 PCB로부터 컨텍스트 불러오기</h3>
</li>
<li>선택된 새 프로세스의 PCB로부터 컨텍스트 정보를 CPU에 불러온다. 이 단계에서 CPU 레지스터, 프로그램 카운터 등이 새 프로세스의 정보로 업데이트 된다.<h3 id="📚-4-작업-전환">📚 4. 작업 전환</h3>
</li>
<li>CPU는 새로운 프로세스의 실행을 시작한다. 이전 프로세스는 필요에 따라 나중에 다시 실행될 준비를 완료한다.</li>
</ul>
<h2 id="📖-pcb에-저장되는-정보">📖 PCB에 저장되는 정보</h2>
<ul>
<li>프로세스 식별자(PID) : 각 프로세스를 고유하게 식별하는 번호</li>
<li>프로세스 상태 : 프로세스의 현재 상태(실행 중, 대기 중, 중지 등)를 나타낸다.</li>
<li>프로그램 카운터 : 프로세스가 다음에 실행할 명령어의 주소를 가리킨다.</li>
<li>CPU 레지스터 : 프로세스가 중지된 시점의 CPU 레지스터 상태를 저장한다.</li>
<li>CPU 스케줄링 정보 : 프로세스의 우선순위, 스케줄링 큐에 대한 정보 등이 포함된다.</li>
<li>메모리 관리 정보 : 프로세스의 메모리 할당 상태, 페이지 테이블, 세그먼트 테이블 등을 포함된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐶CPU코어와 스레드와의 상관관계]]></title>
            <link>https://velog.io/@usa_dev/CPU%EC%BD%94%EC%96%B4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%99%80%EC%9D%98-%EC%83%81%EA%B4%80%EA%B4%80%EA%B3%84</link>
            <guid>https://velog.io/@usa_dev/CPU%EC%BD%94%EC%96%B4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%99%80%EC%9D%98-%EC%83%81%EA%B4%80%EA%B4%80%EA%B3%84</guid>
            <pubDate>Tue, 23 Apr 2024 10:47:12 GMT</pubDate>
            <description><![CDATA[<h1 id="📌개요">📌개요</h1>
<p>CPU 코어 개수와 스레드는 컴퓨터의 성능과 멀티태스킹 능력에 있어 중요한 요소이다.
이들 사이의 상관관계를 이해하려면 먼저 각각의 정으와 기능을 알아야한다.</p>
<h1 id="📖-cpu코어">📖 CPU코어</h1>
<ul>
<li>CPU 코어는 중앙 처리 장치(CPU) 내부에 있는 계산 엔진이다.</li>
<li>각 코어는 독립적으로 명령을 수행할 수 있으며, 여러 코어를 사용하면 동시에 여러 작업을 처리할 수 있다.</li>
<li>코어가 많을수록 일반적으로 CPU가 더 많은 작업을 동시에 처리할 수 있어 멀티태스킹 성능이 향상된다.</li>
</ul>
<h1 id="📖-스레드">📖 스레드</h1>
<ul>
<li>스레드는 프로그램 내에서 실행되는 명령어의 흐름이다.</li>
<li>하나의 프로세스는 하나 이상의 스레드를 가질 수 있다.</li>
<li>운영체제는 이러한 스레드를 스케줄링하여 CPU 시간을 분배한다.</li>
</ul>
<h2 id="📚-하이퍼스레딩">📚 하이퍼스레딩</h2>
<ul>
<li>하나의 물리적 CPU 코어를 두 개의 논리적 코어로 나누어 처리 능력을 증가시키는 기술이다.</li>
<li>각 CPU 코어가 두 개의 스레드를 동시에 처리할 수록 하여 CPU의 자원을 보다 효율적으로 사용할 수 있게 된다. (내가 쓰고 있는 AMD 라이젠5 5600X는 6코어 12스레드다.)</li>
</ul>
<h2 id="📚-상관관계">📚 상관관계</h2>
<ul>
<li>CPU의 코어 수와 스레드 수는 성능과 멀티태스킹 능력에 직접적인 영향을 미친다.</li>
<li>코어 수가 많을수록, 그리고 하이퍼스레딩이 활성화 되어 있을수록 동시에 더 많은 작업을 수행할 수 있으며, 이는 특히 복잡한 작업을 처리하거나 여러 프로그램을 동시에 실행할 때 유리하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐶 클러스터드 인덱스와 논클러스터드 인덱스]]></title>
            <link>https://velog.io/@usa_dev/%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%93%9C-%EC%9D%B8%EB%8D%B1%EC%8A%A4%EC%99%80-%EB%85%BC%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%93%9C-%EC%9D%B8%EB%8D%B1%EC%8A%A4</link>
            <guid>https://velog.io/@usa_dev/%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%93%9C-%EC%9D%B8%EB%8D%B1%EC%8A%A4%EC%99%80-%EB%85%BC%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%93%9C-%EC%9D%B8%EB%8D%B1%EC%8A%A4</guid>
            <pubDate>Sun, 21 Apr 2024 14:34:37 GMT</pubDate>
            <description><![CDATA[<h1 id="📌-개요">📌 개요</h1>
<p>인덱스는 데이터를 빠르게 감색할 수 있는 도와주는 객체이다. 컬럼을 정렬한 후 데이터를 빠르게 찾을 수 있도록 해준다. 책으로 치자면 일종의 색인 역할을 의미한다. 이 인덱스는 두가지 종류로 나뉘는데 상황에 맞게 적절한 컬럼으로 적용하는게 중요하다.</p>
<h2 id="📖-클러스터드-인덱스">📖 클러스터드 인덱스</h2>
<ul>
<li>테이블당 1개씩만 허용된다.</li>
<li>물리적으로 행을 재배열한다.</li>
<li>PK 설정 시 그 컬럼은 자동으로 클러스터드 인덱스가 만들어진다.</li>
<li>인덱스 자체의 리프 페이지가 곧 데이터이다. 즉 테이블 자체가 인덱스이다. (따로 인덱스 페이지를 만들지 않는다.)</li>
<li>데이터 입력, 수정, 삭제 시 항상 인덱스 순서에 따라 저장된다. 즉, 데이터 자체가 인덱스의 일부가 되어 인덱스로서 기능한다.</li>
<li>논클러스터드 인덱스보다 검색속도는 더 빠르다. 하지만 데이터의 입력, 수정, 삭제는 느리다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/b788734e-e002-469c-a580-f5d6a60bc1fc/image.png" alt="">
클러스터드 인덱스를 구성하려면 행 데이터를 해당 열로 정렬한 후에 루트 페이지를 만들게 된다.
즉 데이터 페이지는 리프 노드와 같은 것을 확인할 수 있다.</p>
<h2 id="📖-논클러스터드-인덱스">📖 논클러스터드 인덱스</h2>
<ul>
<li>테이블당 약 240개의 인덱스를 만들 수 있다.</li>
<li>인덱스 페이지는 로그파일에 저장된다.</li>
<li>레코드의 원본은 정렬되지 않고, 인덱스 페이지만 정렬된다.</li>
<li>인덱스 자체의 리프 페이지는 데이터가 아니라 데이터가 위치하는 포인터이기 때문에 클러스터드형보다 검색 속도는 더 느리지만 데이터의 입력, 수정, 삭제는 더 빠르다.</li>
<li>인덱스를 생성할 때 데이터 페이지는 그냥 둔 상태에서 별도의 인덱스 페이지를 따로 만들기 때문에 용량을 더 차지한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/1f520001-9d05-4413-87f0-de6bdf20064a/image.png" alt="">
논클러스터드 인덱스는 데이터 페이지를 건들지 않고, 별도의 장소에 인덱스 페이지를 생성한다.
우선 인덱스 페이지의 리프 페이지에 인덱스로 구성한 열을 정렬하고 데이터 위치 포인터를 생성한다. 데이터의 위치 포인트는 클러스터드형 인덱스와 달리 &#39;페이지 번호 + #오프셋&#39;이 기록되어 바로 데이터 위치를 가리킨다. indexTest2로 예를 들면 102번 페이지의 두 번째(#2)에 데이터가 있다고 기록하게 된다.</p>
<h3 id="📚-정리">📚 정리</h3>
<p>책에 비유하자면 클러스터드 인덱스는 페이지를 알기 때문에 바로 그 페이지를 펴는 것이고, 논클러스터드 인덱스는 뒤에 목차에서 찾고자 하는 내용의 페이지를 찾고 그 페이지로 이동하는 것과 같다. 테이블 풀 스캔은 처음부터 한 장씩 넘기면서 내용을 찾는 것과 같다.</p>
<p>클러스터드 인덱스</p>
<ul>
<li>검색 : 테이블의 데이터를 인덱스 키 기준으로 물리적으로 정렬되어있어 조회할 때 추가적인 참조 없이 직접 데이터에 접근할 수 있어 빠름.</li>
<li>DML : 데이터 삽입과 삭제가 발생할 경우 데이터의 물리적 순서 유지를 위해 페이지 분할이나 복잡한 데이터 이동이 필요할 수 있음.</li>
</ul>
<p>논클러스터드 인덱스</p>
<ul>
<li>검색 : 클러스터드 인덱스와 달리 별도의 공간에서 인덱스 키를 찾은 후 실제 데이터의 위치를 가리키는 포인터를 따라 데이터 파일에서 해당 데이터를 찾아야 해서 클러스터드 인덱스보다 상대적으로 느림.</li>
<li>DML : 데이터 삽입과 삭제가 발생할 경우 인덱스 페이지의 리프 노드만을 업데이트 하면 되기 때문에 빠름.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐶 DB의 인덱스와 자료구조]]></title>
            <link>https://velog.io/@usa_dev/DB%EC%9D%98-%EC%9D%B8%EB%8D%B1%EC%8A%A4%EC%99%80-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@usa_dev/DB%EC%9D%98-%EC%9D%B8%EB%8D%B1%EC%8A%A4%EC%99%80-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Thu, 18 Apr 2024 14:19:07 GMT</pubDate>
            <description><![CDATA[<h1 id="📌-개요">📌 개요</h1>
<p>DB를 사용할 때 데이터의 양에 따라 실행결과의 속도가 차이가 나는 것을 알 수 있다. 이때 RDB의 인덱스를 잘활용하면 쿼리의 성능을 높일 수 있다. 또한 인덱스는 별도의 메모리 공간에 존재하는데 이때 사용되는 자료구조에 대해서도 알아보자.</p>
<h1 id="📖-db-인덱스">📖 DB 인덱스</h1>
<p>인덱스란 <strong>데이터베이스 테이블에 대한 검색 성능의 속도를 높여주는 자료구조</strong> 이다. 특정 컬럼에 인덱스를 생성하면 해당 컬럼의 데이터들을 정렬하여 별도의 메모리 공간에 데이터의 물리적 주소와 함께 저장된다. 인덱스가 생성되었다면 쿼리문에 <strong>인덱스 생성 컬럼을 WHERE 조건</strong>으로 거는 등의 작업을 하면 옵티마이저에서 판단하여 생성된 인덱스를 탈 수 있다.</p>
<p>인덱스에 저장되어 있는 데이터의 물리적 주소로 가서 데이터를 가져오는 식의 동작을 하여 검색 속도의 향상을 가져올 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/85a8fb12-d656-4c82-ab0d-569638d21079/image.png" alt=""></p>
<h2 id="📚-인덱스를-사용할-때-장점과-단점">📚 인덱스를 사용할 때 장점과 단점</h2>
<p>인덱스의 가장 큰 특징은 데이터들이 정렬 되어있다는 점이다. 이 특징이 장점이자 단점이다.</p>
<ul>
<li><p>장점</p>
<ul>
<li><p>조건 검색 WHERE 절의 효율성 증가
  <strong>테이블 안에 데이터가 쌓이게 되면 테이블의 레코드(row)는 내부적으로 순서가 없이 뒤죽박죽으로 저장이된다. 이런경우 WHERE절에 특정 조건에 맞는 데이터들을 찾아낼 때도 레코드의 처음부터 끝까지 다 읽어서 검색 조건과 맞는지 비교해야한다.(풀 스캔) 하지만 인덱스 테이블 스캔 시 인덱스 테이블은 데이터들이 정렬되어 저장되어 있기 때문에 해당 조건에 맞는 데이터들을 빠르게 찾아낼 수 있다. (이것이 인덱스를 사용하는 가장 큰 이유이다.)</strong></p>
</li>
<li><p>정렬 ORDER BY 절의 효율성 증가
  <strong>인덱스를 사용하면 ORDER BY에 의한 정렬과정을 피할 수 있다. ORDER BY는 굉장히 부하가 많이 걸리는 작업이다. 정렬과 동시에 1차적으로 메모리에서 정렬이 이루어지고 메모리보다 큰 작업이 필요하다면 디스크 I/O도 추가적으로 발생하기 때문이다. 하지만 인덱스를 사용하면 이미 정렬이 되어 있기 때문에 가져오기만 하면 된다.</strong></p>
</li>
<li><p>MIN, MAX의 효율적인 처리가 가능하다.
<strong>데이터가 정렬되어 있기 때문에 레코드의 시작 값과 끝 값 한건씩 가져오면 되기 때문에 풀 스캔 후 찾는 것 보다 훨씬 효율적이다.</strong></p>
</li>
</ul>
</li>
<li><p>주의점</p>
<ul>
<li><p>인덱스는 DML에 취약하다.
<strong>INSERT, UPDATE, DELETE를 통해 데이터가 추가되거나 값이 바뀐다면 인덱스 테이블 내에 있는 값들을 다시 정렬을 해야 한다. 인덱스 테이블, 원본 테이블 이렇게 두 군데의 데이터 수정 작업을 해줘야 한다는 단점이 발생한다. 그렇기 때문에 DML이 빈번한 테이블보다 검색을 위주로 하는 테이블에 인덱스를 생성하는 것이 좋다.</strong></p>
</li>
<li><p>무조건 인덱스 스캔이 좋지만은 않다.</p>
</li>
<li><p><em>검색을 위주로 하는 테이블에 인덱스를 생성하는 것이 좋지만 무조건 인덱스가 검색에 좋지만은 않다. 예를 들어 1개의 데이터가 있는 테이블과 100만개의 데이터가 있는 테이블이 있을 때, 100만 개의 데이터가 들어 있는 테이블에서는 풀 스캔보다는 인덱스 스캔이 유리하겠지만 1개의 데이터가 들어있는 테이블은 인덱스 스캔보다 풀 스캔이 더 빠르다.*</em></p>
</li>
<li><p>속도 향상을 위해 인덱스를 많이 만드는 건 좋지 않다.</p>
</li>
<li><p><em>인덱스를 관리하기 위해서는 데이터베이스의 약 10%에 해당하는 저장공간이 추가로 필요하다. 때문에 너무 많이 인덱스를 생성하면 하나의 쿼리문을 빠르게 만들 수 있지만 전체적인 데이터베이스의 성능 부하를 초래한다.*</em></p>
</li>
</ul>
</li>
</ul>
<h1 id="📖-인덱스의-자료구조">📖 인덱스의 자료구조</h1>
<p>이러한 인덱스는 몇 가지 자료구조를 통해 만들어진다. 그 중 가장 대표적인 3가지인 해시 테이블, B-Tree, B+Tree에 대해 알아보자</p>
<h2 id="📚-해시-테이블">📚 해시 테이블</h2>
<p>해시 테이블은 key, value 형태로 데이터를 저장한다. key를 통해 값에 바로 접근하므로 검색 시 O(1)의 복잡도로 빠르게 데이터를 찾을 수 있다. </p>
<p>하지만 key의 등호 연산에만 유리하고 쿼리에서 자주 사용되는 부등호(범위) 연산에는 불리하다.</p>
<h2 id="📚-b-tree">📚 B-Tree</h2>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/bef0b21c-00b6-4673-8a4b-9e6a804a689a/image.png" alt="">
B-Tree를 알아보기 전에 일반적인 Tree가 아닌 왜 B-Tree를 사용하는지 알아둘 필요가 있다.
<img src="https://velog.velcdn.com/images/usa_dev/post/1107dda2-b997-409f-a388-9fc58179425f/image.png" alt="">
일반적인 트리는 이렇게 생겼다. 하지만 어떤 데이터가 추가되고 삭제될지 모르기 때문에 이런저런 DML 작업을 당한 테이블은 이런 형태가 될 수 있다.
<img src="https://velog.velcdn.com/images/usa_dev/post/8b98890b-022d-43ae-b32a-1492c91b75c4/image.png" alt="">
이렇게 한 쪽으로 편향된 트리는 검색을 위해 모든 노드를 순회 해야 하므로 검색 성능이 매우 떨어지게 된다.</p>
<p>그래서 데이터베이스에서는 B-Tree를 사용한다. B는 Balanced의 약자로 언제나 같은 높이의 트리를 유지하기 때문에 검색 성능을 유지 시킬 수 있다.</p>
<p>B-Tree는 아래와 같이 생겼다.</p>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/1d2ff21f-a36f-44d6-a295-28a2a5115da1/image.png" alt=""></p>
<p>값을 찾기 위해서 일반적인 트리처럼 좌, 우측만을 사용하지 않고 노드에 저장된 값 사이의 포인터를 통해 탐색한다.</p>
<p>위 그래프에서 14라는 값을 찾는다고 하면 14는 7과15사에 있으므로 가운데에 연결된(9,11) 노드로 내려가고 14는 11보다 크므로 11의 오른쪽 노드로 내려가서 14라는 값에 도달하게 된다.</p>
<p>노드가 추가 되거나 삭제 될 때는 한 노드에 얼마나 많은 값들이 존재할 수 있는지 체크를 하고 값을 맨 아래 리프노드의 적절한 위치에 넣은 후 제 자리를 찾아가게 된다.</p>
<p>예를 들어 13이라는 값이 추가 되면 최초에는 (12,14)노드 사이에 들어간다. 하지만 위의 트리의 경우 한 노드에 2개 값만 존재할 수 있으므로 13이 한 단계 한 단계 레벨을 올리며 자기 자신의 자리를 찾아가게 된다.</p>
<p>이 과정을 페이징 이라고 한다.</p>
<h2 id="📚-btree">📚 B+Tree</h2>
<p>B-Tree는 데이터의 검색에는 유리하다. 하지만 모든 데이터를 풀 스캔하려면 모든 트리를 전부 방문해야 한다. </p>
<p>이러한 단점을 개선한 것이 B+Tree 이다.</p>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/348e9988-52d4-4da3-8ed3-2a205970616b/image.png" alt=""></p>
<p>B+Tree는 리프 노드에만 데이터를 저장하고 모든 리프노드를 링크드 리스트를 통해 연결한다.</p>
<p>이렇게 하면 리프노드를 제외한 루트, 내부 노드에는 데이터를 저장하지 않기 때문에 메모리가 남고 내부 노드는 더 많은 키 값을 저장할 수 있게 되고, 이는 트리의 높이가 낮아지므로 검색 속도가 빨라진다.</p>
<p>또 테이블 풀스캔을 하는 경우에도 리프 노드에 모든 데이터가 있고 모두 링크드 리스로 연결되어 있으므로 풀 스캔시에도 B-Tree 보다 유리하다. 범위 스캔을 하는 경우에도 링크드 리스트를 통해 효율적인 순차 검색을 할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐶 동기 비동기와  블로킹 I/O 논블로킹 I/O와 Spring MVC vs Spring Webflux 비교]]></title>
            <link>https://velog.io/@usa_dev/%EC%B9%B4%ED%8E%98%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B8%94%EB%A1%9C%ED%82%B9-IO-%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-IO%EC%99%80-Spring-MVC-vs-Spring-Webflux-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@usa_dev/%EC%B9%B4%ED%8E%98%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B8%94%EB%A1%9C%ED%82%B9-IO-%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-IO%EC%99%80-Spring-MVC-vs-Spring-Webflux-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Mon, 15 Apr 2024 11:04:03 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>동기, 블로킹 I/O와 비동기, 논블로킹 I/O를 카페에서의 점원과 고객의 입장으로 설명해보면 쉽게 이해할 수 있다.</p>
</blockquote>
<h1 id="📖-동기와-비동기">📖 동기와 비동기</h1>
<h2 id="📚-동기">📚 동기</h2>
<ul>
<li>동기란 요청 작업들을 순차적으로 처리한다는 의미이다.</li>
<li>점원이 한번에 하나의 주문만 처리하는 경우이다.</li>
<li>한 손님이 주문하고 커피를 받기 전 까지 다른 손님의 주문을 받지 않는다.</li>
<li>모든 주문이 순서대로 하나씩 처리된다.</li>
<li>고객이 딸기 블렌디드 요거트를 주문했다면 길고 긴 <strong>주문-제작-수령</strong>의 과정이 끝나야만 다음 고객이 주문을 할 수가 있게 된다. 딸기 블렌디드 요거트는 <strong>제작</strong> 과정에서 시간이 많이 걸리기 때문에 (마치 DB I/O로 인한 유휴상태) 뒤에 고객은 속이 탈 거다.<h2 id="📚-비동기">📚 비동기</h2>
</li>
<li>비동기란 요청 작업들을 순차적으로 처리하지 않는다는 의미이다.</li>
<li>점원은 카페에 들어온 여러 고객의 주문을 받은 후 각각의 주문을 바리스타에게 전달한다. 그리고 번호표를 통해 나중에 완성되면 번호표를 통해 안내 해준다.</li>
<li>바리스타가 커피를 만들고 있을 때도 점원은 계속해서 다른 고객의 주문을 받을 수 있다.</li>
<li>모든 주문이 순서대로 처리되지 않는다.</li>
<li>고객이 제작과정이 긴 딸기 블렌디드 요거트를 주문했다고 해도 제작은 바리스타가 하고 점원은 번호표를 통해 나중에 음료가 완성되었을때 안내를 해주면 되기 때문에 <strong>긴 제작과정을 무시</strong>하고 다른 주문을 받을 수 있다.<h1 id="📖-블로킹-io와-논블로킹-io">📖 블로킹 I/O와 논블로킹 I/O</h1>
<h2 id="📚-블로킹-io">📚 블로킹 I/O</h2>
</li>
<li>블로킹 I/O란 요청에 결과를 기다리는 것 이다.</li>
<li>점원에게 커피를 받기 전 까지 아무짓도 못하고 부동자세로 멈춰버리는 것 이다.</li>
<li>고객은 커피를 기다리는 시간 동안 다른 일을 할 수 없다.<h2 id="📚-논블로킹-io">📚 논블로킹 I/O</h2>
</li>
<li>논블로킹 I/O란 요청에 결과를 기다리지 않는 것 이다.</li>
<li>고객이 점원에게 주문을 한 뒤 번호표를 받고, 할 일을 하다가 번호표가 호출되면 커피를 받으러 가는 것 이다.</li>
<li>고객은 커피를 기다리는 시간 동안 다른 일을 할 수 있다.</li>
</ul>
<h2 id="📚-정리">📚 정리</h2>
<blockquote>
<p><strong>동기 비동기는 어떤 작업의 순차처리를 할지 말지에 대한 개념이다.
블로킹 I/O와 논블로킹 I/O는 어떤 작업의 결과를 기다릴지 말지에 대한 개념이다.</strong></p>
</blockquote>
<h1 id="📖-spring-webmvc">📖 Spring WebMVC</h1>
<ul>
<li>서블릿 API를 기반으로 한 전통적인 웹 프레임워크</li>
<li>각 요청이 쓰레드 풀과 별도의 스레드에 의해 처리 되는 동기식 접근 방식을 사용</li>
<li>일반적으로 블로킹 I/O를 사용하여 처리</li>
<li>요청당 쓰레드를 생성하므로 많은 수의 동시 연결을 처리할 때 확장성 문제가 발생할 수 있음.</li>
</ul>
<h1 id="📖-spring-webflux">📖 Spring WebFlux</h1>
<ul>
<li>리액티브 스트림즈 사양을 구현하여 비동기 및 논블러킹 방식을 제공</li>
<li>반응형 프로그래밍 모델을 기반으로 구축되어 적은 수의 고정된 스레드로 많은 수의 동시 연결을 처리함.</li>
<li>논블로킹 I/O를 사용하며, Reactive Streams API를 기반으로함</li>
<li>적은 수의 스레드로 대량의 요청을 처리하는 데 더 적합한 반응형 및 논블로킹 접근 방식</li>
</ul>
<h2 id="📚-정리-1">📚 정리</h2>
<blockquote>
<p><strong>스프링 MVC에서는 동기 블러킹 방식으로 동작하기 때문에 사용자의 요청을 동시에 받을 수 는 있지만 A스레드에서 DB I/O 작업 수행 시 해당 스레드는 블러킹되어 유휴상태가 되어 스레드를 효율적으로 운용할 수 없게 된다.
반면, 스프링 WebFlux는 비동기 논블러킹 방식으로 동작하기 때문에 사용자의 요청을 동시에 받으면서도 A스레드에서 DB I/O 작업 수행 시에도 논블러킹으로 동작하기 때문에 유휴상태가 되지 않으므로, 적은 스레드로 더 많은 유저의 요청을 처리할 수 있게 된다.</strong></p>
</blockquote>
<p>참고
<a href="https://pro-self-studier.tistory.com/89">https://pro-self-studier.tistory.com/89</a>
<a href="https://private.tistory.com/24">https://private.tistory.com/24</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐶GC란 무엇이며 STOP THE WORLD는 왜 발생할까?]]></title>
            <link>https://velog.io/@usa_dev/GC%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-STOP-THE-WORLD%EB%8A%94-%EC%99%9C-%EB%B0%9C%EC%83%9D%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@usa_dev/GC%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-STOP-THE-WORLD%EB%8A%94-%EC%99%9C-%EB%B0%9C%EC%83%9D%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Thu, 11 Apr 2024 14:24:40 GMT</pubDate>
            <description><![CDATA[<h2 id="1-gc란">1. GC란</h2>
<p>GC란 자바 애플리케이션에서 사용하지 않는 메모리를 자동으로 수거하는 기능이다.
C/C++같은 언어는 메모리를 할당하고 직접 해제해야 했지만 자바에서는 GC를 이용하여 개발자들이 메모리 관리를 비교적 신경쓰지 않아도 된다.
JVM의 Heap 영역에서 GC가 일어나는데 전통적인 GC는 Heap영역을 고정된 영역인 <strong>Young영역</strong>과 <strong>Old영역</strong>으로 구분한다.</p>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/78d107ee-e130-4d07-937e-aa65606583c7/image.png" alt=""></p>
<h3 id="young-영역">Young 영역</h3>
<ul>
<li>새로운 객체가 할당되는 영역</li>
<li>young영역에서 일어나는 가비지 컬렉션을 Minor GC라고 한다.</li>
</ul>
<p>young영역은 또 다시 3가지 영역으로 구분할 수 있다.</p>
<blockquote>
<p>Eden, Survivor 0, Survivor 1</p>
</blockquote>
<h4 id="eden">Eden</h4>
<ul>
<li>new를 통해 생성된 객체</li>
<li>정기적인 GC 작업 이후 살아남은 객체들은 Survivor로 보내진다.<h4 id="survivor-0-survivor-1">Survivor 0, Survivor 1</h4>
</li>
<li>최소 1번의 GC에서 살아남은 객체가 존재한다.</li>
<li>Survivor 0, Survivor 1 둘 중 하나는 꼭 비어있어야 한다.</li>
</ul>
<h3 id="old-영역">Old 영역</h3>
<ul>
<li>young영역에서 살아남은 객체가 복사되는 영역</li>
<li>young영역보다 크게 할당되며, 영역의 크기가 큰 만큼 GC는 적게 발생한다.</li>
<li>Old 영역의 대한 GC를 Major GC라고 한다.</li>
</ul>
<blockquote>
<p>Old 영역이 Young 영역보다 크게 할당되는 이유는 Young 영역의 수명이 짧은 객체들은 큰 공간을 필요로 하지 않으며, 큰 객체들은 곧바로 Old 영역에 할당되기 때문이다.</p>
</blockquote>
<h2 id="2-gc-동작-방식">2. GC 동작 방식</h2>
<p>Young영역과 Old영역은 서로 다른 메모리 구조로 되어 있기 때문에 세부적은 동작 방식은 다르지만, 기본적으로 가비지 컬렉션이 실행된다고 한다면 다음의 2가지 단계를 따르게 된다.</p>
<p>2-1. Stop The World
2-2. Mark and Sweep</p>
<h3 id="2-1-stop-the-world">2-1. Stop The World</h3>
<p>Stop The World는 가비지 컬렉션을 실행하기 위해 JVM이 애플리케이션의 실행을 멈추는 작업이다. GC가 실행될 때는 GC를 실행하는 쓰레드를 제외한 모든 쓰레드들이 중단된다. 모든 쓰레드들의 작업이 중단된다면 애플리케이션 또한 중단되기 때문에 GC의 성능을 개선한다는 것은 보통 Stop The World 시간을 줄이는 작업을 하는 것이다. </p>
<blockquote>
<p>그래서 왜 하는걸까? 그 이유는 두 가지가 있다.</p>
</blockquote>
<h4 id="메모리-단편화">메모리 단편화</h4>
<p>컴퓨터 시스템에서 메모리 공간을 할당하고 해제하는 과정에서 발생하는 현상이다. 메모리 단편화는 크게 외부 단편화와 내부 단편화로 나뉘는데 외부 단편화는 메모리 할당 및 해제 작업의 반복으로 작은 메모리가 중간중간에 존재해 사용하지 않는 메모리가 존재해서 총 메모리 공간은 충분하지만 실제로 할당할 수 없는 상황이다. 
반면에 내부 단편화는 메모리 공간 중 일부가 할당된 뒤 남는 공간이 발생하는 경우이다. 프로세스에 메모리를 할당할 때 요청된 크키보다 약간 더 큰 메모리 블록이 할당되는 경우가 있는데, 이 때 할당된 블록 내부에서 사용되지 않는 공간이 발생한다.</p>
<p>GC 또한 할당 된 메모리를 해제 하는 과정에서 메모리 공간이 새로 남는데 이를 해결하기 위해 <strong>Compaction</strong>이 일어나야 한다. 이를 위해 객체를 새로운 주소로 이동 시키고 다시 주소를 참조할 수 있게 해줘야 한다. </p>
<h4 id="메모리-일관성유지">메모리 일관성유지</h4>
<p>가비지 컬렉션 과정 중에는 힙 내의 객체들이 이동되거나 메모리에서 해제될 수 있다. 애플리케이션 스레드가 이러한 작업이 진행되는 동안 계속 실행된다면 스레드가 사용하려는 객체가 더 이상 유요하지 않거나 잘못된 위치에 있을 수 있다. 
(Compaction이 발생해서 객체가 이동하는 과정에서 스레드가 의도치 않은 전혀 다른 객체 주소를 참조할 수도 있음)
즉, 애플리케이션 스레드가 객체 참조 시 의도치않은 상황을 피하기 위해서 stop the world를 한다.</p>
<h3 id="2-2-mark-and-sweep">2-2 Mark and Sweep</h3>
<ul>
<li>Mark : 사용되는 메모리와 사용되지 않는 메모리를 식별하는 작업</li>
<li>Sweep : Mark 단계에서 사용되지 않음으로 식별된 메모리를 해제하는 작업</li>
</ul>
<p>stop the world를 통해 모든 작업을 중단시키면 GC는 Reachable 객체를 스캔하면서 사용되고 있는 메모리를 식별한다<strong>(Mark)</strong> 이후 Mark가 되지 않는 객체들을 메모리에서 제거한다<strong>(Sweep)</strong></p>
<h4 id="minor-gc의-동작-방식">Minor GC의 동작 방식</h4>
<p>객체가 새롭게 생성되면 Eden 영역에 할당된다. 그리고 Eden 영역이 꽉 차면 <strong>Minor GC</strong>가 발생하게 되는데, 사용되지 않는 메모리는 해제되고 Eden 영역에 존재하는 객체는 Survivor 영역으로 옮겨지게 된댜. Survivor 영역은 총 2개지만 반드시 1개는 비어있어야 한다. 자세히 살펴본다면 다음과 같다.</p>
<ol>
<li>새로 생성된 객체가 Eden 영역에 할당된다.</li>
<li>객체가 계속 생성되어 Eden 영역이 꽉차게 되고 Minor GC가 실행된다.
 2-1. Eden 영역에서 사용되지 않는 객체의 메모리를 해제한다.
 2-2. Eden 영역에서 살아남은 객체는 1개의 Survivor 영역으로 이동한다.</li>
<li>1~2 번의 과정이 반복되다가 Survivor 영역이 가득차게 되면 Survivor 영역의 살아남은 객체를 다른 Survivor 영역으로 이동시킨다.</li>
<li>이러한 과정을 반복하여 살아남은 객체는 Old영역으로 이동(Promotion)된다.<h4 id="major-gc의-동작-방식">Major GC의 동작 방식</h4>
Young 영역에서 오래 살아남은 객체는 Old영역으로 이동된다. 그리고 Major GC는 객체들이 계속 Promotion 되어 Old 영역의 메모리가 부족해지면 발생하게 된다. Young 영역은 일반적으로 크키가 작기 때문에 GC가 보통 0.5초에서 1초 사이에 끝난다. 그렇기 때문에 Minor GC는 애플리케이션에 크게 영향을 주지 않는다. 하지만 Old 영역은 Young 영역보다 크며 Young영역을 참조할 수도 있다. 그렇기 때문에 일반적으로 Minor GC보다 시간이 오래 걸리며 10배 이상의 시간을 사용한다. 참고로 Young 영역과 Old 영역을 동시 처리하는 GC는 Full GC라고 한다.</li>
</ol>
<h2 id="요약">요약</h2>
<table>
<thead>
<tr>
<th align="center">GC 종류</th>
<th align="center">Minor GC</th>
<th align="center">Major GC</th>
</tr>
</thead>
<tbody><tr>
<td align="center">대상</td>
<td align="center">Young Generation</td>
<td align="center">Old Generation</td>
</tr>
<tr>
<td align="center">실행시점</td>
<td align="center">Eden 영역이 꽉 찬 경우</td>
<td align="center">Old 영역이 꽉 찬 경우</td>
</tr>
<tr>
<td align="center">실행속도</td>
<td align="center">빠르다</td>
<td align="center">느리다</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Virtual Thread란]]></title>
            <link>https://velog.io/@usa_dev/JAVA-Virtual-Thread%EB%9E%80</link>
            <guid>https://velog.io/@usa_dev/JAVA-Virtual-Thread%EB%9E%80</guid>
            <pubDate>Thu, 14 Mar 2024 13:46:47 GMT</pubDate>
            <description><![CDATA[<h2 id="virtual-thread">Virtual Thread</h2>
<p>Java 21는 Java 8 이후 세번째 LTS 버전이다. 이 버전에서는 가장 큰 업데이트인 <strong>가상 스레드</strong>라는 기능이 추가되었다.</p>
<h3 id="가상-스레드란">가상 스레드란?</h3>
<p>가상스레드란 기존의 전통적인 Java 스레드에 더하여 새롭게 추가되는 경량 스레드이다. Project Loom의 결과물로 추가된 기능으로 OS 스레드를 그대로 사용하지 않고 JVM 자체적으로 내부 스케줄링을 통해서 사용할 수 있는 경량의 스레드를 제공한다.</p>
<blockquote>
<p>Project Loom 이란? 경량의 스레드를 Java에 추가하기 위해서 가상 스레드를 비롯한 여러가지 기능들을 개발하는 프로젝트로 Loom이란 단어는 Thread 의 사전적 정의가 ‘실’ 이라는데 착안하여 실을 엮어 ‘직물을 만든다는 뜻‘이다.</p>
</blockquote>
<h2 id="특징">특징</h2>
<ul>
<li><p>경량성 : 가상 스레드는 훨씬 적은 메모리를 사용하여, 일반적인 OS스레드보다 훨씬 많은 수를 생성하고 운영할 수 있다.</p>
</li>
<li><p>간단한 관리 : 가상 스레드는 스레드 풀을 직접 관리할 필요가 없다. 스레드 스케줄링과 관리는 JVM과 라이브러리에 의해 자동으로 처리된다.</p>
</li>
<li><p>블로킹 작업 친화적 : 기존의 스레드 모델에서 블로킹 I/O 작업은 리소스 낭비 문제를 일으킬 수 있었다. 하지만 가상 스레드는 이러한 작업에서도 효율적으로 작동하도록 설계되었다. 따라서 I/O작업이 많은 애플리케이션에서도 성능 저하 없이 사용할 수 있다.</p>
</li>
<li><p>간단한 API : 가상 스레드를 사용하기 위한 API는 매우 간단하다. 기존의 <code>Thred</code> 클래스와 유사한 방식으로 가상 스레드를 생성하고 실행할 수 있으며, 추가적인 학습 곡선이 거의 없다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/acb684e8-6477-4ee3-8239-8bc7e6445413/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/a60c110b-577f-4601-9e2e-885001f426e2/image.png" alt=""></p>
<p>출처 : <a href="https://findstar.pe.kr/2023/04/17/java-virtual-threads-1/">https://findstar.pe.kr/2023/04/17/java-virtual-threads-1/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 2751번 수 정렬하기 2]]></title>
            <link>https://velog.io/@usa_dev/%EB%B0%B1%EC%A4%80python-2751%EB%B2%88-%EC%88%98-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-2</link>
            <guid>https://velog.io/@usa_dev/%EB%B0%B1%EC%A4%80python-2751%EB%B2%88-%EC%88%98-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-2</guid>
            <pubDate>Fri, 17 Nov 2023 15:24:13 GMT</pubDate>
            <description><![CDATA[<p>** 이 문제는 여러개의 데이터를 입력받아 정렬해야 하기 때문에 input()대신 sys.stdin.readline()를 사용해야 시간초과가 발생하지 않는다. 편의를 위해 다음과 같이 작성 후 평소 input()처럼 사용하면 된다.**</p>
<blockquote>
<p>input = sys.stdin.readline</p>
</blockquote>
<p><strong>주의 점으로는 input()의 경우 자동개행을 해주지만 sys.stdin.readline의 경우 직접 개행문자를 입력해줘야만 개행이 된다.</strong></p>
<h3 id="✍️-풀이">✍️ 풀이</h3>
<pre><code class="language-python">import sys
input = sys.stdin.readline # 빠른 입출력과 편의를 위해 input에 sys.stdin.readline을 할당한다.

n = int(input())
L = []
for i in range(n):
    a = int(input())
    L.append(a)
L.sort()

for i in range(len(L)):
    print(L[i])
</code></pre>
<p><strong>설명으로 달아논 주석이 잘못되었다면 댓글로 알려주시면 감사하겠습니다!</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 1018번 체스판 다시 칠하기 ]]></title>
            <link>https://velog.io/@usa_dev/%EB%B0%B1%EC%A4%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98python-1018%EB%B2%88-%EC%B2%B4%EC%8A%A4%ED%8C%90-%EB%8B%A4%EC%8B%9C-%EC%B9%A0%ED%95%98%EA%B8%B0-%ED%8C%8C%EC%9D%B4%EC%8D%AC</link>
            <guid>https://velog.io/@usa_dev/%EB%B0%B1%EC%A4%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98python-1018%EB%B2%88-%EC%B2%B4%EC%8A%A4%ED%8C%90-%EB%8B%A4%EC%8B%9C-%EC%B9%A0%ED%95%98%EA%B8%B0-%ED%8C%8C%EC%9D%B4%EC%8D%AC</guid>
            <pubDate>Fri, 17 Nov 2023 06:05:08 GMT</pubDate>
            <description><![CDATA[<p><strong>아 이번거는 너무 어려워서 해설 봤는데도 이해 하는데 오래걸렸다 .. 난이도 실버 맞나 ..</strong></p>
<p>*<em>이해가 잘 안됐고 놓친 부분이 체스판이 만약 화이트로 시작하면 인덱스 위치의 합이 짝수 일때 해당 인덱스는 모두 화이트여야 하는데 이걸 놓쳤었다 .. *</em></p>
<h3 id="✍️-풀이">✍️ 풀이</h3>
<pre><code class="language-python">N, M = map(int, input().split())
board = list()
for i in range(N):
    board.append(input())
repair = list()

# 체스판 시작 범위 설정
# 만약 가로로 브루트 포스할 때 N이 10일때 10-7하면 3이다. 고로 8x8 체스가 가로로 3번만 움직이게끔 하기 위함
for i in range(N-7):
    # 마찬가지로 세로로 브루트 포스할 때 시작 범위 설정
    for j in range(M-7):
        first_W = 0
        first_B = 0
        # 8x8범위의 체스판으로 검증을 시작한다 검증할 것은 화이트로 체스판이 시작할때 or 블랙으로 시작할때의
        # 해당하는 칸이 옳은 색상의 칸인지를 판별하면된다. 만약 화이트로 체스판이 시작된다면 짝수칸이 모두 화이트여야 한다.
        # 그렇지 않다면 해당하는 칸은 잘못된 칸이기 때문에 first_w를 +1 시킨다 블랙일때도 마찬가지
        for k in range(i,i+8):
            for l in range(j,j + 8):
                # 체스 시작이 화이트일때와 블랙일때 모두 구한다 만약 화이트로 시작을 한다고 쳤을때 짝수는 모두 화이트여야한다.
                # 그런데 만약 화이트(W)가 아니라면 그 칸은 잘못된 색상이기에 first_W +1 시킨다
                if (k + l) % 2 == 0:
                    if board[k][l] != &#39;W&#39;:
                        first_W = first_W + 1
                    if board[k][l] != &#39;B&#39;:
                        first_B = first_B + 1
                # 체스 시작이 화이트일때 홀수칸은 블랙이여야만 한다 근데 B가 아니라면 잘못된 칸이므로 first_W +1 시킨다
                else:
                    if board[k][l] != &#39;B&#39;:
                        first_W = first_W + 1
                    if board[k][l] != &#39;W&#39;:
                        first_B = first_B + 1
        # 이제 화이트일때와 블랙일떄의 다시 페인트를 칠한 횟수중 가장 작은 값을 repair에 추가한다
        repair.append(min(first_W, first_B))
        # 가장 작은 페인트칠을 한 수를 출력
print(min(repair))</code></pre>
<p><strong>설명으로 달아논 주석이 잘못되었다면 댓글로 알려주시면 감사하겠습니다!</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Jenkins] Git Push 시 fatal: could not read Username 에러 해결]]></title>
            <link>https://velog.io/@usa_dev/Jenkins-Git-fatal-could-not-read-Username-no-such-device-or-address-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@usa_dev/Jenkins-Git-fatal-could-not-read-Username-no-such-device-or-address-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Wed, 25 Oct 2023 08:13:00 GMT</pubDate>
            <description><![CDATA[<h2 id="jenkins에서-git-push-인증-에러-해결기-gitops--argocd-환경">Jenkins에서 Git Push 인증 에러 해결기 (GitOps + ArgoCD 환경)</h2>
<p>회사에서 최근 쿠버네티스 환경으로 조금씩 전환하고 있었는데,<br>클러스터 환경 역시 자동화가 필요하다고 느껴 <code>GitOps</code> 라는 개념을 접하게 되었다.</p>
<p>이후 실제 회사 프로젝트에 적용해보려다 꽤 오래 삽질했던 에러를 기록해본다.</p>
<hr>
<h2 id="현재-구성">현재 구성</h2>
<p>전체 흐름은 아래와 같다.</p>
<pre><code class="language-text">Jenkins Build
  ↓
deployment.yaml 이미지 버전 변경
  ↓
Git Push
  ↓
ArgoCD 감지
  ↓
Kubernetes Cluster 자동 반영</code></pre>
<p>Jenkins에서 빌드가 완료되면:</p>
<ul>
<li><code>deployment.yaml</code> 내부의 컨테이너 이미지 태그를</li>
<li>Jenkins Build Number 기준으로 변경 후</li>
<li>Git Repository에 Push</li>
</ul>
<p>하도록 구성했다.</p>
<p>예를 들면:</p>
<pre><code class="language-yaml">image: my-app:123</code></pre>
<p>이런 식으로 자동 업데이트되는 구조다.</p>
<p>그리고 이후 ArgoCD가 Git 변경 사항을 감지하여<br>클러스터 상태를 자동으로 동기화한다.</p>
<hr>
<h2 id="문제-발생">문제 발생</h2>
<p>그런데 Jenkins Pipeline 내부에서 Git Push 시 아래와 같은 인증 에러가 계속 발생했다.</p>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/d2c3e4df-af11-4b06-894d-22df2fee3e27/image.png" alt="에러 이미지"></p>
<hr>
<h2 id="처음-시도했던-방법">처음 시도했던 방법</h2>
<p>Jenkinsfile 상단에서 아래처럼 git 계정 설정도 해주었다.</p>
<pre><code class="language-groovy">sh &#39;git config --global user.email &quot;jenkins@example.com&quot;&#39;
sh &#39;git config --global user.name &quot;jenkins&quot;&#39;</code></pre>
<p>하지만 계속 인증 에러가 발생했다.</p>
<hr>
<h2 id="원인">원인</h2>
<p>결론적으로 문제는:</p>
<pre><code class="language-text">Git 사용자 정보 설정 != Git 인증 정보 저장</code></pre>
<p>이었다.</p>
<p>즉:</p>
<pre><code class="language-bash">git config --global user.name
git config --global user.email</code></pre>
<p>은 단순히 commit 작성자 정보일 뿐,<br>실제 Git Push 인증과는 관련이 없었다.</p>
<hr>
<h2 id="해결-방법">해결 방법</h2>
<p>정말 긴 삽질 끝에 Jenkins 계정으로 직접 접속하여 테스트를 진행했고,<br>수동으로 <code>git push</code> 가 되지 않는 것을 확인했다.</p>
<p>이후 아래 명령어로 credential helper를 설정했다.</p>
<pre><code class="language-bash">git config credential.helper store --global</code></pre>
<p>그 후 Jenkins 계정 상태에서 직접 <code>git push</code> 를 실행하니:</p>
<pre><code class="language-text">Username:
Password:</code></pre>
<p>입력을 요구했고,<br>Git 계정 정보를 입력한 뒤부터 정상적으로 Push가 동작했다.</p>
<hr>
<h2 id="정리">정리</h2>
<p>이번 이슈를 통해 알게 된 점:</p>
<ul>
<li><code>user.name</code>, <code>user.email</code> 은 작성자 정보</li>
<li>실제 Push 인증은 별도</li>
<li>Jenkins 환경에서는 credential 저장 여부가 중요</li>
<li>GitOps 환경에서는 Jenkins ↔ Git 인증 구조를 먼저 확인해야 함</li>
</ul>
<hr>
<h2 id="최종-해결-명령어">최종 해결 명령어</h2>
<pre><code class="language-bash">git config credential.helper store --global</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[도메인 주도 개발 시작하기2 - chapter2]]></title>
            <link>https://velog.io/@usa_dev/%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B02-chapter2</link>
            <guid>https://velog.io/@usa_dev/%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B02-chapter2</guid>
            <pubDate>Mon, 21 Aug 2023 23:29:17 GMT</pubDate>
            <description><![CDATA[<h1 id="chapter2---아키텍처-개요">chapter2 - 아키텍처 개요</h1>
<h2 id="엔티티">엔티티</h2>
<p>고유의 식별자를 갖는 객체 주문, 회원, 상품과 같이
도메인의 고유한 개념을 표현한다. 도메인 모델의 데이터를 포함하며 해당 데이터와 관련된 기능을 함께 제공한다.</p>
<h2 id="밸류">밸류</h2>
<p>고유의 식별자를 갖지 않는 객체로 개념적으로 하나인 값을 표현할 때 사용된다.
배송지 주소를 표현하기 위한 주소나 구매 금액을 위한 금액과 같은 타입이 밸류 타입이다.
엔티티의 속성으로 사용할 뿐만 아니라 다른 밸류 타입의 속성으로도 사용할 수 있다.
(밸류의 경우 불변으로 구현할 것을 권장하며 이 뜻은 엔티티의 밸류 값이 변경된다면 
새로운 객체를 생성해서 처리해야 한다는 뜻이다.)</p>
<h2 id="애그리거트">애그리거트</h2>
<p>애그리거트는 연관된 엔티티와 밸류 객체를 개념적으로 하나로 묶은 것이다.
주문과 관련된 Order 엔티티, Orderline밸류, Orderer밸류 객체를 &#39;주문&#39;애그리거트로 묶을 수 있다.</p>
<p>(일종의 군집화로써 개별 객체가 아닌 관련 객체를 묶어서 객체 군집 단위로 모델을 바라볼 수 있게 된다. 개별 객체 간의 관계가 아닌 애그리거트 간의 관계로 도메인 모델을 이해하고 구현하게 되며, 이를 통해 큰 틀에서 도메인 모델을 관리할 수 있다.</p>
<p>애그리거트는 군집에 속한 객체를 관리하는 &#39;루트&#39;엔티티를 갖는다. 루트 엔티티는 애그리거트에 속해 있는 엔티티와 밸류 객체를 이용해서 애그리거트가 구현해야 할 기능을 제공한다. 애그리거트를 사용하는 코드는 애그리거트 루트가 제공하는 기능을 실행하고 애그리거트 루트를 통해서 간접적으로 애그리거트 내의 다른 엔티티나 밸류 객체에 접근한다. 이것은 애그리거트의 내부 구현을 숨겨 애그리거트 단위로 구현을 캡슐화 할 수 있게 한다.)</p>
<h2 id="리포지터리">리포지터리</h2>
<p>도메인 객체를 지속적으로 사용하려면 RDBMS, NOSQL과 같은 물리적인 저장소에
도메인 객체를 보관해야 한다. 이를 위한 도메인 모델이 리포지터리 Repository이다. 엔티티나
밸류가 요구사항에서 도출되는 도메인 모델이라면 리포지터리는 구현을 위한 도메인 모델이다.</p>
<p>리포지터리는 애그리거트 단위로 도메인 객체를 저장하고 조회하는 기능을 정의한다. 예를들어
주문 애그리거트를 위한 리포지터리를 다음과 같이 정의할 수 있다.</p>
<pre><code class="language-java">public interface  OrderRepository {
    Order findByNumber(OrderNumber number);
    void save(Order order);
    void delete(Order order);
}</code></pre>
<p>OrderRepository의 메서드를 보면 대상을 찾고 저장하는 단위가 애그리거트 루트인 Order인 것을 알 수 있다. Order는 애그리거트에 속한 모든 객체를 포함하고 있으므로 결과적으로 애그리거트 단위로 저장하고 조회한다.</p>
<p>(그러면.. 애그리거트 단위로 저장 및 조회가 된다면 애그리거트 하위 도메인을 조회하기 위해서는 상위 도메인을 통해 조회해야만 한다는 뜻? 그렇다면 불필요한 값도 조회하는건 아닌가 ??) </p>
<p>도메인 모델을 사용해야 하는 코드는 리포지터리를 통해서 도메인 객체를 구한 뒤에 도메인 객체의 기능을 실행한다. 예를 들어 주문 취소 기능을 제공하는 응용 서비스는 다음 코드처럼 OrderRepository를 이용해서 Order 객체를 구하고 해당 기능을 실행한다.</p>
<pre><code class="language-java">public class CancelOrderService {
    private OrderRepository orderRepository;

    public void cancel(OrderNumber number) {
        Order order = orderRepository.findByNumber(number);
        if (order == null) throw new NoOrderException(number);
        order.cancel();
    }
}</code></pre>
<p>도메인 모델 관점에서 OrderRepository는 도메인 객체를 영속화 하는 데 필요한 기능을 추상화한 것으로 고수준 모듈에 속한다. 기반 기술을 이용하여 OrderRepository를 구현한 클래스는 저수준 모듈(세부사항)로 인프라스트럭처 영역에 속한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[토비의 스프링 부트 - 이해와 원리]]></title>
            <link>https://velog.io/@usa_dev/%ED%86%A0%EB%B9%84%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@usa_dev/%ED%86%A0%EB%B9%84%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Thu, 17 Aug 2023 11:21:56 GMT</pubDate>
            <description><![CDATA[<h1 id="스프링-부트란">스프링 부트란</h1>
<blockquote>
<p>스프링 부트는 스프링을 기반으로 실무 환경에 사용 가능한 수준의 독립실행형 애플리케이션을 복잡한 고민 없이 빠르게 작성할 수 있게 도와주는 여러가지 도구의 모음이다.</p>
</blockquote>
<p>스프링 부트의 핵심 목표</p>
<ul>
<li>매우 빠르고 광범위한 영역의 스프링 개발 경험을 제공</li>
<li>강한 주장을 가지고 즉시 적용 가능한 기술 조합을 제공하면서, 필요에 따라 원하는 방식으로 손쉽게 변형 가능</li>
<li>프로젝트에서 필요로 하는 다양한 비기능적인 기술(내장형 서버, 보안, 메트릭, 상태 체크, 외부 설정 방식 등) 제공</li>
<li>코드 생성이나 XML 설정을 필요로 하지 않음</li>
</ul>
<h1 id="containerless-개발">Containerless 개발</h1>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/97b3f0f6-b8de-487b-894a-a1c22d4ec0ab/image.png" alt=""></p>
<p>스프링 애플리케이션 개발에 요구되는 서블릿 컨테이너의 설치, WAR 폴더 구조, web.xml,
WAR 빌드, 컨테이너로 배치, 포트 설정, 클래스로더, 로깅 등과 같은 필요하지만 애플리케
이션 개발의 핵심이 아닌 단순 반복 작업을 제거해주는 개발 도구와 아키텍처 지원한다
설치된 컨테이너로 배포하지 않고 독립실행형(standalone) 자바 애플리케이션으로 동작</p>
<h1 id="스프링의-설계-철학">스프링의 설계 철학</h1>
<ul>
<li>극단적인 유연함 추구</li>
<li>다양한 관점을 수용</li>
<li>Not opinionated (주장을 고집하지 않는다)</li>
<li>수많은 선택지를 다 포용</li>
</ul>
<p>스프링은 너무나도 포용적이기 때문에 이런저런 고민들이 생겨날 수 있음</p>
<h1 id="스프링-부트의-설계-철학">스프링 부트의 설계 철학</h1>
<ul>
<li>Opionionated - 자기 주장이 강한, 자기 의견을 고집하는, 독선적인</li>
<li>일단 정해주는 대로 빠르게 개발하고 고민은 나중에</li>
<li>스프링을 잘 활용하는 뛰어난 방법을 제공</li>
<li>업계에서 검증된 스프링 생태계 프로젝트, 표준 자바 기술, 오픈소스 기술의 종류와 의존관계, 사용버전을 정해줌 (jpa를 예로 들자면 hibernate 구현체를 꽂아줌)</li>
<li>각 기술을 스프링에 적용하는 방식(DI구성)과 디폴트 설정값 제공</li>
</ul>
<h1 id="스프링-부트의-이해">스프링 부트의 이해</h1>
<ul>
<li>부트가 결정한 기술과 구성, 디폴트 설정을 수용</li>
<li>외부 설정 파일을 이용한 설정 변경 방법을 활용</li>
<li>아주 빠르게 개발을 시작할 수 있다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[운영체제] 프로세스와 스레드]]></title>
            <link>https://velog.io/@usa_dev/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C</link>
            <guid>https://velog.io/@usa_dev/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C</guid>
            <pubDate>Thu, 08 Jun 2023 14:02:01 GMT</pubDate>
            <description><![CDATA[<h2 id="1-프로그램과-프로세스">1. 프로그램과 프로세스</h2>
<p><strong>프로그램은 저장장치에 저장되어 있는 정적인 상태이고, 프로세스는 실행을 위해 메모리에 올라온 동적인 상태이다.</strong></p>
<h2 id="2-프로세스의-상태">2. 프로세스의 상태</h2>
<ul>
<li>생성 상태: 프로그램을 메모리에 가져와 실행 준비가 완료된 상태.</li>
<li>준비 상태: 실행을 기다리는 모든 프로세스가 자기 차례를 기다리는 상태. 실행될 프로세스를 CPU 스케줄러가 선택하게됨.</li>
<li>실행 상태: 선택된 프로세스가 타임 슬라이스를 얻어 CPU를 사용하는 상태이다. 프로세스 사이의 문맥 교환이 일어난다.</li>
<li>대기 상태: 실행 상태에 있는 프로세스가 입출력을 요청하면 입출력이 완료될 때까지 기다리는 상태이다. 입출력이 완료되면 준비 상태로 간다.</li>
<li>완료 상태: 프로세스가 종료된 상태이다. 사용하던 모든 데이터가 정리됨. 정상 종료인 exit와 비정상 종료인 abort를 포함한다.</li>
</ul>
<h2 id="3-프로세스-제어-블록">3. 프로세스 제어 블록</h2>
<p><strong>프로세스를 실행하는데 필요한 중요한 정보를 보관하는 자료구조로, 모든 프로세스는 고유의 프로세스 제어 블록을 가진다. 프로세스 제어 블록은 프로세스 생성 시 만들어져서 프로세스가 실행을 완료하면 폐기한다. 다양한 정보 중 대표적인 세가지는 다음과 같다.</strong></p>
<ul>
<li>프로세스 구분자: 프로세스를 구분하기 위한 프로세스 구분자(PID).</li>
<li>메모리 관련 정보: CPU는 실행하려는 프로세스가 메모리의 어디에 저장되어 있는지를 알아야 한다. 이를 위한 프로세스의 메모리 위치 정보와 메모리 보호를 위한 경계 레지스터와 한계 레지스터도 포함되어 있다. </li>
<li>각종 중간값: 프로세스 제어 블록에는 프로세스가 사용했던 중간 값이 저장되는데 이는 여러 프로세스가 번갈아가며 실행되는데 만약 A프로세스 에서 50번 행까지 작업을 했다가 B프로세스에게 CPU를 넘겨주었고, 다시 A프로세스의 차례가 되면 51번 행 코드를 실행시켜야 하기 때문.</li>
</ul>
<h2 id="4-문맥-교환">4. 문맥 교환</h2>
<p><strong>두 프로세스의 프로세스 제어 블록 및 이와 관련된 값들을 교환하는 작업을 말한다. 일반적으로 문맥 교환은 한 프로세스가 자신에게 주어진 시간을 다 사용하면 발생하고, 인터럽트가 걸렸을 때도 발생한다.</strong></p>
<h2 id="5-프로세스의-복사와-전환">5. 프로세스의 복사와 전환</h2>
<ul>
<li>fork() 시스템 호출: 실행 중인 프로세스로부터 새로운 프로세스를 복사하는 함수이다.(자식 프로세스 생성됨)</li>
<li>exec() 시스템 호출: 기존의 프로세스를 새로운 프로세스로 전환하는 함수이다. 해당 방식은 프로세스 구조를 재활용하는 방식으로써 프로세스는 그대로 둔 채 내용만 바꾸는 시스템 호출이다. exec() 시스템 호출을 하면 현재의 프로세스가 완전히 다른 프로세스로 전환된다. 
(프로세스를 새로 메모리에 올리지 않고 기존 프로세스의 구조체를 활용하기 위함)</li>
</ul>
<h2 id="6-프로세스의-계층-구조">6. 프로세스의 계층 구조</h2>
<p><strong>부모 프로세스를 복사하여 자식 프로세스를 만드는 방법으로 프로세스끼리 계층 구조를 갖는 것을 말한다. 부모 프로세스는 자신의 자원을 자식 프로세스에 상속하고 자식 프로세스가 종료되면 그 자원을 회수한다.</strong></p>
<h2 id="7-스레드">7. 스레드</h2>
<p><strong>CPU 스케줄러가 CPU에 전달하는 일 하나를 스레드라고 하며, 하나의 프로세스에는 여러개의 스레드가 존재하기도 한다.</strong></p>
<h2 id="8-스레드-관련-용어">8. 스레드 관련 용어</h2>
<ul>
<li>멀티스레드: 멀티스레드는 프로세스 내 작업을 여러 개의 스레드로 분할함으로써 작업의 부담을 줄이는 프로세스 운영 기법이다.(스레드들은 데이터를 공유함.)</li>
<li>멀티태스킹: 운영체제가 CPU에 작업을 줄 때 시간을 잘게 나누어 배분하는 기법이다.</li>
<li>멀티프로세싱: CPU를 여러 개 사용하여 여러 개의 스레드를 동시에 처리하는 작업 환경을 말한다.</li>
<li>CPU 멀티스레드: 한 번에 하나씩 처리해야 하는 스레드를 파이프라인 기법을 이용하여 동시에 여러 스레드를 처리하도록 만든 병렬 처리 기법이다.</li>
</ul>
<h2 id="9-멀티스레드의-장점">9. 멀티스레드의 장점</h2>
<ul>
<li>응답성 향상: 한 스레드가 입출력으로 인해 작업이 진행되지 않더라도 다른 스레드가 작업을 계속하여 사용자의 작업 요구에 빨리 응답할 수 있다.</li>
<li>자원 공유: 한 프로세스 내에서 독립적인 스레드를 생성하면 프로세스가 가진 자원을 모든 스레드가 고융하게 되어 작업을 원활하게 진행할 수 있다.</li>
<li>효율성 향상: 불필요한 자원의 중복을 막음으로써 시스템의 효율이 향상된다.</li>
<li>다중CPU 지원: 2개 이상의 CPU를 가진 컴퓨터에서 멀티스레드를 사용하면 다중 CPU가 멀티스레드를 동시에 처리하여 CPU 사용량이 증가하고 프로세스의 처리 시간이 단축 된다.</li>
</ul>
<h2 id="느낀점">느낀점</h2>
<ul>
<li>프로세스의 여러 상태에 대해 알 수 있었다.</li>
<li>문맥 교환이 일어났을때 프로세스 제어 블록을 활용하여 기존 작업내역을 담아두어 여러 프로세스들을 관리함을 알 수 있었다.</li>
<li>멀티스레드와 멀티프로세싱에 대해 명확히 알 수 있었다<ul>
<li>웹 브라우저인 크롬과 익스플로어를 예로 설명하자면 크롬의 경우 멀티프로세싱을 활용한 브라우저로써 각 탭마다 각각의 프로세스를 생성하지만, 익스플로어의 경우 멀티스레드를 활용한 브라우저로써 각 탭마다 스레드를 생성한다. 즉, 익스플로어의 경우 하나의 프로세스에서 각 스레드가 자원을 공유하기 때문에 1번탭이 멈추면 2번탭 3번탭 또한 작동이 안된다. 반면 크롬의 경우 각각의 탭이 각자의 프로세스 영역이기에 메모리 효율은 좋지 못하지만 1번 탭이 멈춰도 2번탭 3번탭은 영향이 없다.</li>
<li>익스플러어는 과거에 만들어져 메모리의 용량이 충분치 못하여 자원을 아끼기위해 멀티스레드로 구현한걸까? 현대사회는 개인이 가지는 PC의 메모리의 용량이 갈수록 거대해지는데 내가 자바로 코딩을할때 자원을 아끼는것이 좋을까 아님 협업을 위한 가독성 좋은 코드를 짜는것이 중요할까?</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[첫 오프라인 컨퍼런스 인프콘 2022 후기]]></title>
            <link>https://velog.io/@usa_dev/%EC%B2%AB-%EC%98%A4%ED%94%84%EB%9D%BC%EC%9D%B8-%EC%BB%A8%ED%8D%BC%EB%9F%B0%EC%8A%A4-%EC%9D%B8%ED%94%84%EC%BD%98-2022-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@usa_dev/%EC%B2%AB-%EC%98%A4%ED%94%84%EB%9D%BC%EC%9D%B8-%EC%BB%A8%ED%8D%BC%EB%9F%B0%EC%8A%A4-%EC%9D%B8%ED%94%84%EC%BD%98-2022-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Sat, 27 Aug 2022 08:09:17 GMT</pubDate>
            <description><![CDATA[<p><strong>첫 컨퍼런스였던 인프콘 2022 후기를 남겨보려 한다</strong></p>
<h1 id="입장">입장</h1>
<p><strong>이번 인프콘은 강남 코엑스에서 열렸다. 문자로 날아온 QR코드를 보여주고 입장키트를 받았다.</strong>
<img src="https://velog.velcdn.com/images/usa_dev/post/16a9d971-4108-4129-ba49-9a3ac49b6f53/image.png" alt=""></p>
<p><strong>티셔츠, 볼펜, 마스크, 스티커 등등이 들어있었고, 들어가자마자 참여기업들의 부스들의 눈에 띄었다.</strong></p>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/ff17db29-7f9d-4e20-b0ed-04647a780d3e/image.jpg" alt="">
<strong>각 기업 부스에 참여해서 설문조사를 진행하면 굿즈와 참여스탬프를 찍어주는데 3개당
돌려돌려돌림판을 돌릴 수 있다.(인프런 강의 할인 등등의 상품)</strong></p>
<h2 id="오프닝">오프닝</h2>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/c042e6de-6eb8-4269-8c0e-90edc468b887/image.jpg" alt="">
<strong>인프런 CTO 동욱님께서 앞으로의 인프런이 지향하는 바에 대한 설명과 인프런 이용자들에 대한 감사인사를 하셨다.</strong>
<img src="https://velog.velcdn.com/images/usa_dev/post/35ea25e1-fa2a-4c3b-ad7f-ccf515ef8035/image.jpg" alt="">
<strong>오프닝이 끝난 후 동욱님과 사진을 찍었다 ㅎㅎ 피지컬이.. 장난 아니시다 ^^..</strong></p>
<h2 id="각종-세션들">각종 세션들</h2>
<p><strong>각종 세션들 중 가장 기억에 남았던 세션은 요즘 관심가지고 있는 DevOps관련 세션이였는데</strong>
<img src="https://velog.velcdn.com/images/usa_dev/post/d0663ef9-fc8c-4706-bc35-e80a92f6976e/image.jpg" alt="">
<strong>DevOps를 해야하는 이유를 잘 나타내주는 한 컷인거 같다 ㅋㅋ</strong></p>
<h2 id="마지막으로-영한님-세션">마지막으로 영한님 세션</h2>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/c78f6d0c-f5a9-466e-bf6c-e6f976485c20/image.jpg" alt="">
*<em>영한님 세션엔 개발자 커리어에 대한 조언같은 것들을 해주셨다. 그리고 시스템을 만들어
내가 어느회사를 들어가야지가 아닌 회사를 최종목표점으로 잡고 공부에대한 시스템을 만들어 지속적인 성장을 이뤄내는것이 중요하다는 내용이였다. (시스템을 갖추자) *</em></p>
<h2 id="후기">후기</h2>
<p><img src="https://velog.velcdn.com/images/usa_dev/post/e035a846-fbbd-4a51-8977-22e35f584b34/image.jpg" alt="">
<strong>이로써 나의 첫 컨퍼런스가 끝났다. 여러 기업들의 굿즈들도 바리바리 받아왔으며, 세션들도 너무 알찼다. 다음번엔 혼자가 아닌 동료 개발자와 같이 참가했으면 좋겠다 ㅎㅎ</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JVM - JDK, JRE, JVM이란? ]]></title>
            <link>https://velog.io/@usa_dev/JVM-JDK-JRE-JVM%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@usa_dev/JVM-JDK-JRE-JVM%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Thu, 18 Aug 2022 05:32:39 GMT</pubDate>
            <description><![CDATA[<h2 id="🔴jdkjava-development-kit란">🔴JDK(Java Development Kit)란?</h2>
<p><strong>말 그대로 java로 소프트웨어 개발을 할 수 있도록 여러 기능들을 제공하는 패키지다.</strong></p>
<h3 id="🔴jdk구성은-간략히">🔴JDK구성은 간략히</h3>
<ul>
<li><p><strong>javac : 자바 컴파일러, 자바 소스파일을 바이트코드로 변환</strong></p>
</li>
<li><p><strong>java : javac가 만든 클래스 파일을 해석 및 실행</strong></p>
</li>
<li><p><strong>jar : 서로 관련있는 클래스 라이브러리들과 리소스를 하나의 파일로 만들어주는 툴</strong></p>
</li>
<li><p><strong>jdb : 자바 디버깅 툴</strong></p>
</li>
<li><p><strong>JRE(Java Runtime Enviroment) : java가 동작하는데 필요한 JVM, 라이브러리 등 
다양한 파일들을 포함한다. java를 실행만 할꺼면 요거만 설치받으면 된다.</strong></p>
</li>
<li><p><strong>JVM(Java Virtual Machine) : java가 실제로 동작하는 가상환경.</strong></p>
</li>
</ul>
<h2 id="🟠jrejava-runtime-environment이란">🟠JRE(Java Runtime Environment)이란?</h2>
<ul>
<li><p><strong>자바 런타임 환경이라는 뜻이다.</strong></p>
</li>
<li><p><strong>JVM을 실행할 수 있는 최소한의 라이브러리를 포함한 것.
(AWT, Swing, JDBC, JNDI, 컬렉션 프레임워크, 기본 설정 API 등등등..  )</strong></p>
</li>
<li><p><strong>JRE는 JVM의 실행환경을 구현했다고 할 수 있다.</strong></p>
</li>
<li><p><strong>JDK 설치 시 포함되어 있으며 JRE만 따로 설치 할 수도 있다</strong></p>
</li>
</ul>
<h2 id="🟡jvmjava-virtual-machine이란">🟡JVM(Java Virtual Machine)이란?</h2>
<ul>
<li><strong>java는 os에 종속적이지 않다는 특징이 있음</strong></li>
<li>**즉, OS에 종속받지 않고 cpu가 java를 인식, 실행할 수 있게 하는 가상 컴퓨터 이다.</li>
<li>*</li>
<li><strong>JRE에서 만들어 준 바이트 코드를 각 운영체제에 맞는 기계어로 바꾸어 
실행 될 수 있는 환경을 제공.</strong></li>
</ul>
<h3 id="🟡jvm의-세가지-구성요소">🟡JVM의 세가지 구성요소</h3>
<ul>
<li><strong>Class Loader</strong></li>
<li><strong>Runtime Data Areas</strong></li>
<li><strong>Execution Engine</strong></li>
</ul>
<h1 id="❗주요-차이점">❗주요 차이점</h1>
<ul>
<li><strong>JDK는 개발 플랫폼이고 JRE는 실행용이다.</strong></li>
<li><strong>JVM은 Java 프로그래밍 언어의 기초 또는 핵심이며 프로그램의 Java 소스 코드가 플랫폼에 구애 받지 않도록 한다..</strong></li>
<li><strong>JVM은 JDK와 JRE모두에 포함되어 있으며, JVM없이는 java 프로그램이 실행되지 않음.</strong></li>
</ul>
<h1 id="❕보완-기술">❕보완 기술</h1>
<p><strong>JVM, JRE 또는 JDK를 향상 시키는데 사용할 수 있는 많은 보완 기술이 있다.</strong></p>
<ul>
<li><p><strong>JIT(Just-In-Time Compiler) 는 인터프리터 방식의 단점을 보완하기 위해 도입되었고, 
JVM의 일부이며 바이트 코드를 기계 코드로 변환하는 것을 최적화 한다. 동시에 컴파일할 유사한 바이트 코드를 선택하여 바이트 코드에서 기계 코드 컴파일까지의 전체 기간을 줄인다.</strong></p>
</li>
<li><p><strong>Javac는 java를 읽고 JVM에서 실행할 수 있는 바이트 코드로 변환하는 컴파일러 이다.</strong></p>
</li>
<li><p><strong>Javadoc은 API문서를 Java 소스 코드에서 HTML로 변환한다. 이것은 HTML로 표준 문서를 생성할 때 유용함.</strong></p>
</li>
</ul>
<p><strong>참조사이트</strong>
<a href="https://www.ibm.com/kr-ko/cloud/learn/jre">https://www.ibm.com/kr-ko/cloud/learn/jre</a>
<a href="https://www.ibm.com/cloud/blog/jvm-vs-jre-vs-jdk?mhsrc=ibmsearch_a&amp;mhq=JVM">https://www.ibm.com/cloud/blog/jvm-vs-jre-vs-jdk?mhsrc=ibmsearch_a&amp;mhq=JVM</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[도커 트러블 슈팅 - Got permission denied while trying to connect to the Docker daemon socket]]></title>
            <link>https://velog.io/@usa_dev/%EB%8F%84%EC%BB%A4-%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-Got-permission-denied-while-trying-to-connect-to-the-Docker-daemon-socket</link>
            <guid>https://velog.io/@usa_dev/%EB%8F%84%EC%BB%A4-%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-Got-permission-denied-while-trying-to-connect-to-the-Docker-daemon-socket</guid>
            <pubDate>Tue, 09 Aug 2022 05:49:18 GMT</pubDate>
            <description><![CDATA[<h2 id="이슈발견-시점">이슈발견 시점</h2>
<p><strong>해당 이슈는 현재 회사에서 gitlab CI/CD를 사용중인데 테스트 중 발견했다.</strong></p>
<h2 id="이슈발생-이유">이슈발생 이유</h2>
<p>*<em>해당 계정에서 docker사용 권한이 없기 때문이다. *</em></p>
<h2 id="이슈해결-방법">이슈해결 방법</h2>
<p> ** 1. gitlab-ci.yml에서 리눅스 명령어 &quot;id&quot;를 작성 후 gitlab runner가 사용하는 
 계정 &quot;gitlab-runner&quot;임을 알아냄**</p>
<p> ** 2. 해당 서버에 cat /etc/passwd로 &quot;gitlab-runner&quot; 계정 확인 후 docker권한 없음을 확인**</p>
<p> ** 3. 리눅스 명령어 sudo usermod -a -G docekr gitlab-runner로 권한 부여 후 해결**</p>
]]></description>
        </item>
    </channel>
</rss>