<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>WL(NA+S)</title>
        <link>https://velog.io/</link>
        <description>minj-j`s Development diary!</description>
        <lastBuildDate>Mon, 26 Feb 2024 15:23:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>WL(NA+S)</title>
            <url>https://velog.velcdn.com/images/minj-j/profile/1227fe62-b0cb-4b99-a1db-4d06fb0309ac/image.jfif</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. WL(NA+S). All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/minj-j" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[TDD] Junit4/Mockito 용어정리 ]]></title>
            <link>https://velog.io/@minj-j/Junit4Mockito</link>
            <guid>https://velog.io/@minj-j/Junit4Mockito</guid>
            <pubDate>Mon, 26 Feb 2024 15:23:01 GMT</pubDate>
            <description><![CDATA[<h1 id="mockito">Mockito</h1>
<p>mock : 모조품이라는 뜻
Mockito는 오픈소스 mock 프레임워크이다.
모조품이라는 뜻과 같이 테스트를 위한 <code>가짜 객체</code>를 만들어주는 프레임워크이다.</p>
<h2 id="mockitojunitrunner">MockitoJUnitRunner</h2>
<pre><code class="language-java">// 이렇게 사용
@RunWith(MockitoJUnitRunner.class)</code></pre>
<p>Mockito가 제공하는 Junit 확장 클래스로써
JUnit4에서 Mockito를 사용하여 테스트 클래스를 실행할 수 있게 해준다</p>
<h2 id="injectmocks">@InjectMocks</h2>
<p>Mock 객체가 주입되어야 하는 필드를 표시하는데 사용한다.</p>
<pre><code class="language-java">public class MyServiceTest {

    @InjectMocks
    private MyController myController;

    @Mock
    private SomethingService somethingService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testMyServiceMethod() {
        // 테스트 코드 작성
    }
}</code></pre>
<p>MyController 클래스의 객체인 myController에 @InjectMocks이,
SomethingService 클래스의 객체인 somethingService 필드에는 
@Mock 애노테이션이 지정되어 있다. </p>
<p>이렇게 함으로써 myController에 객체에는 자동으로 목 객체인 somethingService가 주입되어 테스트를 수행할 수 있게 된다.</p>
<p>때문에 @InjectMocks를 사용하면</p>
<pre><code class="language-java">public class MyTest {

    private MyController myController에; // 주입할 대상 객체
    private SomethingService somethingService; // 의존 객체

    @Before
    public void setup() {
        somethingService = new SomethingService(); // 명시적으로 의존 객체 생성
        myController에 = new MyController(somethingService); // 의존 객체를 주입하여 MyController 객체 생성
    }

    @Test
    public void testSomeMethod() {
        // userService의 메서드를 호출하고 테스트 진행
    }
}</code></pre>
<p>이렇게 일일이 의존객체를 주입해 줄 필요가 없다는 것이다.</p>
<h2 id="mock">@Mock</h2>
<p>Mockito 프레임워크에서 사용되며, Mock 객체를 생성하는데 쓰인다.
Mock 객체는 실제 객체와 유사하게 동작하나,
개발자가 직접 제어할 수 있는 &quot;가짜&quot;객체이다.</p>
<p>Mock 어노테이션을 사용하여 Mock 객체를 생성할 수 있다
이렇게 생성된 Mock 객체는 실제 객체의 동작을 흉내낸다.
개발자는 객체의 동작을 원하는 대로 설정할 수 있다.</p>
<pre><code class="language-java">import org.junit.Before;
import org.junit.Test;

@Mock
// SomethingService라는 클래스를 테스트 하기 위해 somthingService라는 가짜 객체를 만들었다. 
SomethingService somthingService;
</code></pre>
<h2 id="test">@TEST</h2>
<p>테스트 메서드임을 알리는 어노테이션</p>
<h2 id="mockitowhen">Mockito.when()</h2>
<p>Mock 객체의 동작을 설정하기 위해 사용되는 메서드
특정한 메서드가 호출될 때, 어떤 동작을 하라~ 라고 정의할 수 있다.</p>
<p>단위 테스트시 <code>TEST Stub</code>을 만들 수 있게 해준다.
<code>* stub : 테스트 대상 모듈에 의해 호출되는 프로그램</code></p>
<h3 id="when의-메서드-3가지추후-추가예정">when의 메서드 3가지(추후 추가예정)</h3>
<pre><code>1) thenReturn()
Mock 객체의 특정 메서드 호출에 대한 반환 값을 설정하는데 사용한다.
이때, 반환 값은 특정 메서드가 return하는 값의 형식과 일치해야 한다.</code></pre><pre><code class="language-java">@TEST
public void 테스트_메서드() throws Exception {
    /* somthingService의 selectSomeList()라는 메서드는
    return pageInfo를 반환한다고 가정하자*/

    PageInfo pageInfo = new PageInfo();
    Mockito.when(somthingService.selectSomeList()).thenReturn(pageInfo);

    /* 이런 식으로 thenReturn에는 selectSomeList() 라는
    해당 메서드의 반환형식과 일치하도록 하여 
    테스트 메서드에서의 반환 값을 결정할 수 있다.
    다른 형식은 안됨.
    */
}</code></pre>
<pre><code>2) thenAnswer()
3) </code></pre><p>개인적으로 이걸 왜 쓰지 했는데 챗지피티가 잘 말해줘서
인상깊었던 이유 2개 들고와 봤다.</p>
<blockquote>
</blockquote>
<p>1) 의도한 테스트 시나리오 정의: 목 객체를 사용하여 실제 코드와의 상호작용을 시뮬레이션할 때, 특정 메서드 호출에 대한 반환 값을 설정하여 특정 상황에서 어떻게 동작해야 하는지 명확하게 정의할 수 있습니다.
2) 의존성 관리: 테스트 대상 클래스가 다른 클래스나 서비스와 의존성을 갖는 경우, 이러한 의존성을 목 객체로 대체하여 테스트를 단순화할 수 있습니다. 이 때 when() 메서드를 사용하여 의존하는 메서드 호출에 대한 반환 값을 제어할 수 있습니다.</p>
<h2 id="mockitoverify">Mockito.verify()</h2>
<p>Mock 객체의 메서드가 특정한 방식으로 호출되었는지를 검증할 수 있다.</p>
<pre><code class="language-java">// 기본적인 사용법..
verify(mockObject, verificationMode).methodCall();

@TEST
public void 테스트_메서드() throws Exception {
    PageInfo pageInfo = new PageInfo();
    Mockito.when(somthingService.selectSomeList()).thenReturn(pageInfo);

    //Mockito.times(n) : Mock 객체의 특정 메서드(selectSomeList) 호출이 n만큼 이루어 졌는가를 확인
    Mockito.verify(somthingService, Mockito.times(1)).selectSomeList();
    // =&gt; somthingService라는 Mock객체에서 selectSomeList라는 메서드가 1번 호출이 되었는가 
}</code></pre>
<h1 id="junit4">Junit4</h1>
<p>JAVA용 단위 테스트 프레임워크</p>
<h2 id="runwith">@RunWith</h2>
<p>해당 테스트 클래스를 실행할 때 사용할 테스트 실행기를 지정하는 데에 사용됨
나는 @RunWith(MockitoJUnitRunner.class)를 사용했지만
상황에 따라 () 괄호 안에 다른 실행기가 들어갈 수 있음 </p>
<h2 id="before">@Before</h2>
<p>Junit 프레임워크에서 사용되는 어노테이션
테스트 메서드가 실행되기 전에 실행할 메서드를 지정할 때 사용한다.</p>
<p>이 메서드는 테스트 메서드가 실행되기 전에 반드시 1번 실행된다.
테스트 전 초기화 작업으르 위해 사용</p>
<pre><code class="language-java">import org.junit.Before;
import org.junit.Test;

@Mock
SomethingService somthingService;

@Before
public void setup() {
    // 위에 선언한 mock 객체(somthingService)로 mock 객체 초기화
    MockitoAnnotaions.initMocks(this); 
}</code></pre>
<h2 id="assert새로운거-배울때마다-추가예정">Assert(새로운거 배울때마다 추가예정)</h2>
<ul>
<li>Assert.assertEquals(x,y)
  : 객체 x(예상값)와 y(실제값)가 일치하면 테스트가 성공한다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[log4j] log4j:WARN ~ 오류]]></title>
            <link>https://velog.io/@minj-j/Error-log4jWARN-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@minj-j/Error-log4jWARN-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Mon, 26 Feb 2024 13:10:23 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>log4j:WARN Not appenders could be found for logger(..)
log4j:WARN Please initialize the log4j system properly</p>
</blockquote>
<p>테스트 코드 만들다가 이런 오류를 발견했다.</p>
<p>log4j가 적절하게 설정되지 않았기 때문에 생긴 오류였는데</p>
<pre><code class="language-java">import org.apache.log4j.BasicConfigurator; (추가)

public class MyTest {
    ...(생략)

    @Test
    public void 테스트_코드() throws Exception {
        BasicConfigurator.configure(); (추가)
        ...(테스트 코드 이어서 작성)
    }
}</code></pre>
<p>이렇게 추가해 줬더니 해결됐다.
그럼 컨트롤러 상에 찍어둔 로그들 콘솔창에 찍힘</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[순차적 자료구조 : stack, queue, deque, linked list]]></title>
            <link>https://velog.io/@minj-j/%EC%88%9C%EC%B0%A8%EC%A0%81-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-stack-queue-deque-linked-list</link>
            <guid>https://velog.io/@minj-j/%EC%88%9C%EC%B0%A8%EC%A0%81-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-stack-queue-deque-linked-list</guid>
            <pubDate>Sun, 25 Feb 2024 14:51:13 GMT</pubDate>
            <description><![CDATA[<h1 id="stack-queue-dequeue">Stack, Queue, Dequeue</h1>
<p>배열, 리스트와 다린 제한된 접근(삽입, 삭제)만 허용한다.</p>
<h2 id="stack">Stack</h2>
<p>LIFO 구조
중간 삽입과 삭제가 불가능 하다
위로만 나갔다 들어올 수 있다.
아래가 막혀있는 구조</p>
<h2 id="queue">Queue</h2>
<p>FIFO 구조
위아래가 뚫려있다.
아래것이 나가야 그 다음것이 나갈 수 있다.</p>
<h2 id="dequeue">Dequeue</h2>
<p>stack과 Queue를 합친것
위아래가 뚫려있고, 위에서 아래로 아래에서 위로 나가는 것이 가능하다</p>
<h1 id="linked-list">Linked List</h1>
<p>연결 리스트,
연속되지 않은 메모리공간에 데이터가 저장된 형태이다.
(앞의 배열, 리스트, 큐들은 연속된 공간이다)</p>
<p>[3, 2, 0, 5] 라는 연결리스트가 있다면</p>
<p>[ 3, 2가 저장된 곳의 주소 값]
[ 2, 0이 저장된 곳의 주소 값]
[ 0, 5가 저장된 곳의 주소 값]
[ 5, C에선 null, Python에선 none이 저장된다]</p>
<p>이런 형태로 연결리스트는 저장된다.
그래서 인덱스로 접근할 수가 없다. 
저장된 주소값을 타고타고 들어가며 값을 찾아야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[순차적 자료구조 : 배열과 리스트]]></title>
            <link>https://velog.io/@minj-j/%EC%88%9C%EC%B0%A8%EC%A0%81-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@minj-j/%EC%88%9C%EC%B0%A8%EC%A0%81-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Sun, 25 Feb 2024 14:42:08 GMT</pubDate>
            <description><![CDATA[<h1 id="배열과-리스트">배열과 리스트</h1>
<p>가장 기본적인 순차적 자료구조로 중요하다
index 값으로 임의오 원소에 접근할 수 있는 자료구조 이다</p>
<h1 id="배열">배열</h1>
<p>인덱스로 배열 특정위치에 있는 값을 
상수시간 내에 제공할 수 있는 자료구조</p>
<h2 id="c언어에서의-배열">C언어에서의 배열</h2>
<p>A | 2 | 4 | 0 | 5 |
A라는 배열에 숫자가 이렇게 들어있다 가정하다</p>
<p>배열 A라는 원소에는 배열 A의 시작주소가 담겨있다.</p>
<p>ex) 주소값이 100이라 치면 이렇게 되어 있는것
A    | 2 | 4 | 0 | 5 |
주소 | 100 |  ?  |  ?  |  ?  |</p>
<p>그럼 <code>A[2]</code>의 주소는 어떻게 되는 가
정수는 하나에 4byte이므로
<code>A[2]의 주소 = A[0]주소 + 2 * 4byte = 108</code> 이 되는 것이다.</p>
<h1 id="리스트">리스트</h1>
<p>배열과 달리 용량 자동 조절이 가능하다는 특징이 있다</p>
<h2 id="c언어-배열">C언어 배열</h2>
<p>int A[4] 라고 선언했으면 딱 정수 4개만큼의 공간만 할당한다.
새로 공간을 할당하고 싶다면</p>
<pre><code class="language-C">B = (int*) malloc(6*4) # 얘는 공간 할당을 위한 임시 배열이다
A = B # 최종적으로 A에 다시 할당해 줘야함</code></pre>
<p>malloc(memory allocation)을 활용하여 공간을 재할당 해줘야 한다.</p>
<h2 id="python의-list">Python의 list</h2>
<p>파이썬에서 list는 클래스 이다</p>
<p>A  = [ 2, 4, 0, 5 ]
라는 배열이 있을 때, 파이썬의 리스트는
A라는 배열 원소에 값을 저장하는게 아니라</p>
<p>2, 4, 0, 5 라는 객체들은 각각 다른 메모리에 저장되어 있는데,
A[0]..등등은 2, 4, 0, 5 숫자들이 저장된 메모리의 주소를 가리키고 있다.</p>
<p>ex) A[2] = A[2] + 1 이렇게 A[2]를 재정의 한다고 가정해 보자
그럼 0이 없어지는 것이 아니라 0은 그대로 있고 
0 + 1된 값 1이 저장된 메모리 주소를 가리키는 것으로 
가리키는 대상을 바꾸는 것이다</p>
<blockquote>
<p>한국외대 컴전학부 신찬수 교수님의 자료구조 유튜브 강의를 듣고 정리
<a href="https://www.youtube.com/watch?v=buJBlTsWlW0&amp;list=PLsMufJgu5933ZkBCHS7bQTx0bncjwi4PK&amp;index=7">https://www.youtube.com/watch?v=buJBlTsWlW0&amp;list=PLsMufJgu5933ZkBCHS7bQTx0bncjwi4PK&amp;index=7</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조] 기본 용어]]></title>
            <link>https://velog.io/@minj-j/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B8%B0%EB%B3%B8-%EC%9A%A9%EC%96%B4</link>
            <guid>https://velog.io/@minj-j/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B8%B0%EB%B3%B8-%EC%9A%A9%EC%96%B4</guid>
            <pubDate>Sun, 25 Feb 2024 14:15:39 GMT</pubDate>
            <description><![CDATA[<h1 id="자료구조">자료구조</h1>
<ul>
<li>자료 == data</li>
<li>구조<ul>
<li>data의 저장공간,</li>
<li>data의 연산,<ul>
<li>연산 : 읽기, 쓰기, 탐색, 새 데이터 삽입, 기존 자료 삭제
이 모든 것을 통튼 것</li>
</ul>
</li>
</ul>
</li>
</ul>
<h1 id="알고리즘">알고리즘</h1>
<p>자료구조를 통한 입력 데이터로
유한한 횟수의 연산을 이용해 문제를 푸는 것</p>
<h1 id="시간복잡도">시간복잡도</h1>
<p>가장 안좋은 입력에 대한 기본 연산 횟수를 측정하는 것</p>
<ul>
<li>알고리즘 수행 시간
  최악의 입력에 대한 기본 연산 횟수
기본연산
배정연산
대입연산
복사연산
산술연산 : +, -, *, /
비교연산 : &lt;, &lt;=, &gt;, &gt;=, ==, !=
논리연산 : AND, OR, NOT
비트연산<ul>
<li>이런 연산들을 1단위시간 에 할 수 있다 가정하고
시간 복잡도를 구함<h1 id="big---o">Big - O</h1>
알고리즘 수행시간</li>
</ul>
</li>
</ul>
<p>T1(n) = 2n-1 = O(n)
T2(n) = 4n+1 = O(n)
T3(n) = 3/2n^2-3/2n+1 = O(n^2)
T4(a) = a+1 = O(1)</p>
<p>최고차항들이 증가율을 결정한다.
증가율이 클수록 기본연산도 많이 한다.
그래서 O()은 각 식의 최고차항으로 표시한다.</p>
<blockquote>
<p>한국외대 컴전학부 신찬수 교수님 유튜브 강의 보고 정리
<a href="https://www.youtube.com/playlist?list=PLsMufJgu5933ZkBCHS7bQTx0bncjwi4PK">https://www.youtube.com/playlist?list=PLsMufJgu5933ZkBCHS7bQTx0bncjwi4PK</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Maven] 빌드 오류 : Errors occurred during the build....Could not calculate build plan...]]></title>
            <link>https://velog.io/@minj-j/Maven-%EB%B9%8C%EB%93%9C-%EC%98%A4%EB%A5%98-Errors-occurred-during-the-build....Could-not-calculate-build-plan</link>
            <guid>https://velog.io/@minj-j/Maven-%EB%B9%8C%EB%93%9C-%EC%98%A4%EB%A5%98-Errors-occurred-during-the-build....Could-not-calculate-build-plan</guid>
            <pubDate>Thu, 07 Sep 2023 15:37:51 GMT</pubDate>
            <description><![CDATA[<pre><code>Errors occurred during the build....Could not calculate build plan...</code></pre><p>어딘가에서 프로젝트를 불러왔든지 뭘 하고 Maven Update 해야징 했는데
이런 오류가 나왔다면</p>
<p>누군가 작성했거나 자신이 작성한 setting.xml을 파일을 열어본다.
그리고 이 태그들 사이에 있는 setting.xml 파일의 경로를 살펴본다.</p>
<pre><code>&lt;localRepository&gt;....&lt;/localRepository&gt;</code></pre><p>아마 <code>\사용자명\.m2\repository</code> 쪽에 위치시키는 것이 대부분일 것이다. 근데 setting.xml 파일이 있는 경로가 localRepository에 잘못 선언되어 있다면 maven 빌드가 되지 않는다.</p>
<p>나는 사용자명을 잘못 입력해서 빌드가 안됐다.</p>
<p>🐻‍❄️(바보)🐻‍❄️</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 관습적인 추상화 구조 속Impl]]></title>
            <link>https://velog.io/@minj-j/Spring-%EA%B4%80%EC%8A%B5%EC%A0%81%EC%9D%B8-%EC%B6%94%EC%83%81%ED%99%94-%EA%B5%AC%EC%A1%B0-%EC%86%8DImpl</link>
            <guid>https://velog.io/@minj-j/Spring-%EA%B4%80%EC%8A%B5%EC%A0%81%EC%9D%B8-%EC%B6%94%EC%83%81%ED%99%94-%EA%B5%AC%EC%A1%B0-%EC%86%8DImpl</guid>
            <pubDate>Thu, 07 Sep 2023 15:23:41 GMT</pubDate>
            <description><![CDATA[<p>Impl을 그냥 값 return 시키는 용도로만 알고 있다가
너무 뭘 모르는 것 같아서 왜 이렇게 프로젝트를 구성하는지 찾아보았다.</p>
<p>Impl을 설명하는 여러 글들을 찾아본 결과 
<code>인터페이스</code>와 각 서비스 인터페이스에 대한 <code>구현체 클래스</code>로 이루어진 
<code>관습적인 추상화 구조</code>였다는 답을 얻을 수 있었다.</p>
<p>Impl과 이를 활용한 추상화 구조에 대해 알게 된 것들을 더 정리해 보면서
현재 진행 중인 프로젝트의 구조를 더 잘 이해해보고자 한다.</p>
<h1 id="impl-클래스를-사용하는-이유">Impl 클래스를 사용하는 이유</h1>
<p>여기서 관습적인 추상화 구조라는 제목의 의미 부터 알아야 한다.
관습이라 한 이유는 대부분의 스프링 프로젝트에서 Servcie나 DAO를 구현 할 때,
service.java를 인터페이스로, serviceImpl를 구현체 클래스로 만들어서 사용하기 때문이다.
<code>ex) errorCodeService.java / errorCodeServiceImpl.java</code>
<code>ex) errorCodeDAO.java / errorCodeDAOImpl.java</code></p>
<h3 id="1-객체지향-프로그래밍oop의-원칙을-지키기-위해">1. 객체지향 프로그래밍(OOP)의 원칙을 지키기 위해</h3>
<p><code>다형성</code> <code>개방-폐쇄의 원칙</code>
인터페이스를 사용하면 특정 기능에 대한 변경사항이 있을 시,
이를 쉽게 변경할 수 있다. 구현체를 수정하더라도 
다른 코드에 영향을 주지 않기 때문이다.</p>
<p>즉, DAOImpl, ServiceImpl에 코드 수정을 하더라도(확장엔 열려있고)
컨트롤러나 그 외 코드를 수정할 필요가 없다는 것이다.(변경엔 닫혀있는)</p>
<p>거창하진 않지만 예시를 들어보겠다.</p>
<pre><code class="language-java">SomthingDAOImpl.java

public class SomethingDAOImpl implements SomethingDAO {

    @Override
    public List&lt;SomeDTO&gt; selectSomethingList(SomeDTO somes) throws Exception {
        return sqlSession.selectList(namespace+&quot;.selectSomethingList&quot;, somes)
    }
}</code></pre>
<pre><code class="language-java">SomthingServiceImpl.java

public class SomethingServiceImpl implements SomethingService {
    private SomethingDAO somthingDAO;

    @Override
    public List&lt;SomeDTO&gt; selectSomethingList(SomeDTO somes) throws Exception {
        return somthingDAO.selectSomethingList(somes)
    }
}</code></pre>
<p>대애충 이정도의 DAO 구현체와 Servcie 구현체가 있다고 치자.
여기서 DAOImpl의 return 값을 </p>
<pre><code class="language-java">...
sqlSession.selectList(namespace+&quot;.selectAnythingList&quot;, somes)
...</code></pre>
<p>이렇게 바꾸어도 ServiceImpl의 내용은 바꿀 필요가 없다는 것이다.
왜냐하면 Dao내에 있는 메소드를 가져와 리턴하는 것이기 때문에
DAO 구현체가 어떻게 변경이 되든 ServiceImpl는 잘 바뀐 값만 들고와서 리턴해주면 되는 것이다.</p>
<h3 id="2-객체에-대한-설계와-이를-구현한-코드는-바뀔-수-있기-때문에">2. 객체에 대한 설계와 이를 구현한 코드는 바뀔 수 있기 때문에</h3>
<p>Impl을 적용한 프로젝트 대부분은 인터페이스와 구현체가 1:N 관계가 아닌
1:1일 것이라고 한다.</p>
<p>인터페이스를 만드는 이유가 이를 이용하여 코드의 확장성과 재활용성을 높이기 위함인데, 당장 내가 속한 프로젝트도 1:1이다.</p>
<p>그럼에도 이런 구조를 지향하는 이유는 
(예전부터 이렇게 해왔으니까라는 이유가 80%인 것 같지만)
1:N의 관계가 나올 가능성을 염두하지 않을 수 없기에 이같은 형태가
관습적으로 굳어진 것 같다.</p>
<blockquote>
<p>References</p>
</blockquote>
<ol>
<li>관습적인 추상화 Service, ServiceImpl 구조를 사용해야 할까?
<a href="https://wildeveloperetrain.tistory.com/49">https://wildeveloperetrain.tistory.com/49</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조] Hash Table]]></title>
            <link>https://velog.io/@minj-j/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Hash-Table</link>
            <guid>https://velog.io/@minj-j/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Hash-Table</guid>
            <pubDate>Sun, 03 Sep 2023 05:34:26 GMT</pubDate>
            <description><![CDATA[<p>(key, value)로 데이터를 저장하는 자료구조 중 하나
데이터의 크기에 관계 없이 빠르게 데이터를 검색할 수 있다.
그래서 해시테이블의 평균 시간복잡도는 O(1)이다.</p>
<h1 id="hashing">Hashing</h1>
<p>임의의 길이의 값을 해시함수를 사용해 고정된 크기의 값으로 변환하는 작업</p>
<h1 id="hashtable">HashTable</h1>
<p>그리고 HashTable은 이 해싱 작업을 사용하여 데이터를 저장하는 자료구조 이다.</p>
<h2 id="direct-address-table">Direct Address Table</h2>
<p>키 값을 주소로 사용하는 테이블 키 값이 21이면 배열 인덱스 21에 원하는 데이터를 저장할 수 있다. 가장 간단한 형태의 해시테이블</p>
<p>Insert, Searching, Deletion 작업 모두에 O(1)의 시간 복잡도를 가진다.</p>
<h3 id="단점">단점</h3>
<ol>
<li>최대 키 값을 알고 있어야 한다.</li>
<li>최대 값이 작을 때 더 효율적이다.</li>
<li>최대 값과 총 레코드 수와 많이 다르면 메모리 공간 낭비가 일어 날 수 있다.</li>
</ol>
<h1 id="해시-값이-충돌">해시 값이 충돌</h1>
<p>충돌이 발생하지 않는 해시 테이블의 탐색, 삽입, 삭제 연산은 
O(1)의 시간복잡도를 가지나
충돌이 발생하면 O(k)까지 걸리게 된다.</p>
<p>이는 같은 인덱스에 모든 키 값과 데이터가 저장된 경우라
모든 알고리즘 수행 단계에서 충돌이 발생했음을 의미한다.</p>
<p>때문에 이 충돌을 최대한으로 줄여 연산속도를 빠르게 만드는 것이
해시테이블의 핵심이다.</p>
<h1 id="충돌을-해결하는-방법">충돌을 해결하는 방법</h1>
<h2 id="1해시-테이블-구조-개선">1.해시 테이블 구조 개선</h2>
<h3 id="1-1-chaining">1-1. Chaining</h3>
<p>해시 테이블에서 충돌 발생시 충돌이 발생한 (데이터-키값)들을 동일한 버킷에 저장하는데
이 버킷내의 (데이터-키값)을 연결리스트 형태로 저장하는 방법이다.</p>
<h3 id="1-2-open-addressing">1-2. Open Addressing</h3>
<p>원래는 해시 함수로 얻은 해시 값에 따라 (데이터-키값)을 저장하나
동일한 주소에 다른 데이터가 있다면 다른 주소도 이용할 수 있게 하는 방법이다.</p>
<h4 id="open-addressing의-3가지-충돌-처리-기법">Open Addressing의 3가지 충돌 처리 기법</h4>
<ul>
<li><p>1-2-1. 선형 탐사
  가장 기본적인 충돌해결기법,
  충돌이 일어난 지점에서 바로 인접한 인덱스에 데이터를 삽입하기 때문에 데이터가 밀집되는 클러스터링 문제가 발생한다.
  이로 인해 탐색과 삭제가 느려지게 되는 문제가 발생한다.</p>
</li>
<li><p>1-2-2. 제곱 탐사
  충돌이 일어난 인덱스에서 제곱을 하며 탐사를 하는 방식으로
  선형 탐사보다는 탐색과 삭제에 효율적일 수 있다. (더 폭넓게 탐사를 하니까!)
  그러나 초기 해시값을 탐사할 경우에는 클러스터링 문제가 발생 할 수있다.</p>
</li>
<li><p>1-2-3. 이중 해싱
  선형탐사와 제곱 탐사에서 발생하는 클러스터링 문제를 피하기 위해 도입되었다.
  처음 해시 함수로는 해시값을 찾기 위해 사용되고,
  두번째 해시 함수는 충돌이 발생했을 때, 탐사 폭을 계산하기 위해 사용된다.</p>
</li>
</ul>
<h3 id="🙄사담">🙄사담</h3>
<p>지금까지 풀어본 해시 관련 코딩 테스트 문제들을 보면
딕셔너리를 활용하여 얼마나 빨리 값에 접근할 수 있는지를 보는 것 같았다.
코테에서 위에 기술한 지식까지는 사용되진 않는듯..?</p>
<blockquote>
<p>references</p>
</blockquote>
<ol>
<li>Data Structure and Algorithms - Hash Table
<a href="https://www.tutorialspoint.com/data_structures_algorithms/hash_data_structure.htm">https://www.tutorialspoint.com/data_structures_algorithms/hash_data_structure.htm</a></li>
<li>[DS] 해쉬 테이블(Hash Table)이란?
<a href="https://baeharam.netlify.app/posts/data%20structure/hash-table">https://baeharam.netlify.app/posts/data%20structure/hash-table</a></li>
<li>Hashing Data Structure
<a href="https://www.geeksforgeeks.org/hashing-data-structure/">https://www.geeksforgeeks.org/hashing-data-structure/</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] __init__(self) 가 무엇일까]]></title>
            <link>https://velog.io/@minj-j/Python-initself-%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@minj-j/Python-initself-%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Sun, 20 Aug 2023 12:44:55 GMT</pubDate>
            <description><![CDATA[<p>파이썬도 자바와 같이 Class와 메서드를 선언할 수 있다.
메서드 : 클래스 내에 정의된 함수</p>
<h2 id="init-이란">init 이란</h2>
<p><code>__init__</code></p>
<p><strong>init</strong>(self)는 생성자, constructor로 불리며
초기화 initialize 메서드 라고도 한다.
객체가 생성될 때, 자동으로 호출되는 메서드를 의미한다.
객체의 초기값을 설정해야 할 때 사용한다.</p>
<pre><code class="language-python">class Calcul:
    def __init__(self, first, second) -&gt; None:
        self.first = first
        self.second = second

    # 이렇게 데이터를 설정해 주는 함수를 만들어 주기 보다 생성자를 활용하여 초기값을 설정하는게 안전한다.
    # setdata 함수 없이도 add 함수는 __init__을 통해 할당된 숫자들로 연산이 가능하다.
    def setdata(self, first, second):
        self.first = first
        self.second = second

    def add(self):
        result = self.first + self.second
        return result

a = Calcul(5,3)
print(a.first) # 5
print(a.add()) # 8</code></pre>
<h2 id="self">Self</h2>
<p>self는 인스턴스 자기 자신을 의미한다</p>
<p>인스턴스 : 클래스에 의해 만들어진 객체</p>
<pre><code class="language-python">class Person:
    def __init__(self):
        self.hello = &#39;안녕하세요.&#39;

    def greeting(self):
        print(self.hello)

james = Person()
james.greeting()    # 안녕하세요.</code></pre>
<p>여기에서 <strong>init</strong> 의 매개변수 self에 들어가는 값은 Person() 이라고 할 수 있다.</p>
<p>이렇게 Person()이 들어감으로써 self가 완성된 뒤 james에 할당이 된다.</p>
<pre><code class="language-python">james = Person()</code></pre>
<p>그리고 Person 내의 메서드를 호출하면, 현재 인스턴스 즉 james가 greeting 메소드의 self로 들어가게 된다.
james는 클래스 Person의 인스턴스 이므로 greeting은 <strong>init</strong> 에 선언 된 self.hello의 값을 사용할 수 있게 된다.</p>
<pre><code class="language-python">james.greeting()    # 안녕하세요.</code></pre>
<p>아래 사진을 보면 이해가 쉬워질 것 같다.
<img src="https://velog.velcdn.com/images/minj-j/post/32fc1c54-7b2e-4f04-933c-1c4fbbc4cac6/image.png" alt=""></p>
<blockquote>
<p>reference</p>
</blockquote>
<ol>
<li><a href="https://dojang.io/mod/page/view.php?id=2373">https://dojang.io/mod/page/view.php?id=2373</a></li>
<li><a href="https://www.geeksforgeeks.org/__init__-in-python/">https://www.geeksforgeeks.org/__init__-in-python/</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조] Python으로 MinHeap, MaxHeap 구현해보기]]></title>
            <link>https://velog.io/@minj-j/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Python%EC%9C%BC%EB%A1%9C-MaxHeap-%EA%B5%AC%ED%98%84%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@minj-j/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Python%EC%9C%BC%EB%A1%9C-MaxHeap-%EA%B5%AC%ED%98%84%ED%95%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Sun, 20 Aug 2023 01:59:51 GMT</pubDate>
            <description><![CDATA[<h2 id="minheap">MinHeap</h2>
<pre><code class="language-python">class MinHeap(object):
    def __init__(self):
        self.queue = []

    def insert(self, n):
        self.queue.append(n)
        last_index = len(self.queue) - 1

        if last_index &lt; 0 :
            return -1
        parent_index = self.parent(last_index)

        while 0 &lt;= last_index:
            if 0 &lt;= last_index and self.queue[last_index] &lt; self.queue[parent_index]:
                self.swap(last_index, parent_index)
                last_index = parent_index
            else:
                break

    def delete(self):
        last_index = len(self.queue) -1
        if last_index &lt; 0:
            return -1
        self.swap(0, last_index)
        minv = self.queue.pop()
        self.minheapyfiy(0)
        return minv

    def minheapyfiy(self, n):
        left_index = self.leftChilde(n)
        right_index = self.rightChild(n)
        min_index = n

        if left_index &lt;= len(self.queue) -1 and self.queue[left_index] &lt; self.queue[min_index]:
            min_index = left_index
        if right_index &lt;= len(self.queue) -1 and self.queue[right_index] &lt; self.queue[min_index]:
            min_index = right_index

        if min_index != n:
            self.swap(n, min_index)
            self.minheapyfiy(min_index)


    def parent(self, n):
        return (n - 1) // 2

    def swap(self, i, parent_index):
        self.queue[i], self.queue[parent_index] = self.queue[parent_index], self.queue[i]

    def leftChilde(self, index):
        return (index * 2) + 1

    def rightChild(self, index):
        return (index * 2) + 2

    def printHeap(self):
        print(self.queue)

if __name__==&quot;__main__&quot;:
    mh = MinHeap()
    mh.insert(1)
    mh.insert(3)
    mh.insert(11)
    mh.insert(6)
    mh.insert(5)
    mh.insert(2)
    mh.printHeap()
    mh.delete()
    mh.printHeap()
</code></pre>
<h2 id="maxheap">MaxHeap</h2>
<pre><code class="language-python">class MaxHeap(object):

    def __init__(self):
        self.queue = []

    # 새로운 노드 삽입 시 부모노드와 값 비교
    def insert(self, n):
        self.queue.append(n)
        last_index = len(self.queue) - 1
        if last_index &lt; 0:
            return -1
        parent_index = self.parent(last_index)

        while 0 &lt;= last_index:
            if 0 &lt;= last_index and self.queue[parent_index] &lt; self.queue[last_index]:
                self.swap(last_index, parent_index)
                last_index = parent_index
            else:
                break

    # 가장 위 루트 노드가 삭제 된다.(제일 큰 수)    
    def delete(self):
        last_index = len(self.queue) - 1
        if last_index &lt; 0:
            return -1
        self.swap(0, last_index) # 루트 노트가 pop 되면 가장 마지막 노드를 루트 노드에 넣은 뒤 값을 비교해 가며 재정렬 한다.
        maxv = self.queue.pop() # 맨 마지막에 위치한 max값 출력
        self.maxHeapify(0)
        print(maxv)
        return maxv

    def maxHeapify(self, i):
        left_index = self.leftChild(i)
        right_index = self.rightChild(i)
        max_index = i

        if left_index &lt;= len(self.queue) -1 and self.queue[max_index] &lt; self.queue[left_index]:
            max_index = left_index
        if right_index &lt;= len(self.queue) -1 and self.queue[max_index] &lt; self.queue[right_index]:
            max_index = right_index

        if max_index != i:
            self.swap(i, max_index)
            self.maxHeapify(max_index)

    def parent(self, index):
        return (index - 1) // 2

    def swap(self, index, parent_index):
        self.queue[index], self.queue[parent_index] = self.queue[parent_index], self.queue[index]

    def leftChild(self, index):
        return index * 2 + 1

    def rightChild(self, index):
        return index * 2 + 2

    def printHeap(self):
        print(self.queue)

if __name__==&quot;__main__&quot;:
    mh = MaxHeap()
    mh.insert(1)
    mh.insert(3)
    mh.insert(11)
    mh.insert(6)
    mh.insert(5)
    mh.insert(2)
    mh.printHeap()
    mh.delete()
    mh.printHeap()</code></pre>
<blockquote>
<p>reference
<a href="https://daimhada.tistory.com/108">https://daimhada.tistory.com/108</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[LeetCode/Python] 1464. Maximum Product of Two Elements in an Array]]></title>
            <link>https://velog.io/@minj-j/LeetCodePython-1464.-Maximum-Product-of-Two-Elements-in-an-Array</link>
            <guid>https://velog.io/@minj-j/LeetCodePython-1464.-Maximum-Product-of-Two-Elements-in-an-Array</guid>
            <pubDate>Sun, 13 Aug 2023 13:40:54 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p><img src="https://velog.velcdn.com/images/minj-j/post/2d9db6ae-eb84-4733-a2fe-35da4b392379/image.png" alt=""></p>
<p><a href="https://leetcode.com/problems/maximum-product-of-two-elements-in-an-array/">no.1464 문제링크</a></p>
<h3 id="풀이-과정">풀이 과정</h3>
<p>큰 수와 그 다음으로 큰 수를 찾아야 했기에
우선 힙을 반대로 돌리는 과정을 거쳤다 그리고 heappop으로 루트에 있는 수들을 꺼낸 뒤, 그들의 곱을 return 하였다.</p>
<h3 id="풀이-결과">풀이 결과</h3>
<pre><code class="language-python">import heapq

class Solution:
    def maxProduct(self, nums: List[int]) -&gt; int:
        heap =[]
        max_heap = []

        for s in nums:
            heapq.heappush(heap, (-s, s))

        while heap:
            max_heap.append(heapq.heappop(heap)[1])

        first_max = max_heap[0] - 1
        second_max = max_heap[1] - 1

        return first_max * second_max</code></pre>
<h3 id="다른-사람의-풀이">다른 사람의 풀이</h3>
<pre><code class="language-python">class Solution(object):
    def maxProduct(self, nums):

        first, second = 0, 0

        for number in nums:

            if number &gt; first:
                # update first largest and second largest
                first, second = number, first

            elif number &gt; second:
                # update second largest
                second = number

        return (first - 1) * (second - 1)</code></pre>
<p>큰 수들을 계속해서 갱신시키는 방법으로 풀었다.
나는 heapq 모듈을 사용해보고 싶어 heapq를 주로 사용하였는데,
이런 방법도 있는 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[운영체제] 커널이란?]]></title>
            <link>https://velog.io/@minj-j/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EC%BB%A4%EB%84%90%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@minj-j/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EC%BB%A4%EB%84%90%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 13 Aug 2023 12:31:25 GMT</pubDate>
            <description><![CDATA[<h1 id="kernel-커널">Kernel 커널</h1>
<p>운영체제 중 항상 메모리 상에 있는 운영체제의 핵심부, 
하드웨어와 응용프로그램 사이에서 인터페이스를 제공하는 역할을 함.
CPU, 메모리 등의 컴퓨터 자원을 조작하고 접근하고 관리하는 역할도 한다.</p>
<p>** 인터페이스 : 서로 다른 두 개의 시스템, 장치 사이에서 정보나 신호를 주고받는 경우의 접점이나 경계면</p>
<h2 id="이중-모드">이중 모드</h2>
<p>CPU가 사용자에게서 받은 명령어를 실행하는 모드를 2가지로 구분하는 방식
<em><strong>사용자 모드</strong>_와 **_커널 모드</em>**가 있다.</p>
<ul>
<li><p>사용자 모드
  운영체제 서비스를 제공받을 수 없는 실행 모드, 커널 영역의 코드를 실행할 수 없다.
  일반적인 응용 프로그램은 이 사용자 모드로 실행이 된다.</p>
</li>
<li><p>커널 모드
  운영체제 서비스를 제공받을 수 있는 실행 모드
  CPU가 커널 모드로 명령어를 실행하면 컴퓨터 자원에 접근하는 명령어를 비롯하여 모든 명령어를 실행할 수 있다.</p>
</li>
</ul>
<h2 id="추상화">추상화</h2>
<p>하나뿐인 하드웨어를 마치 여러개인 것 처럼 보여지도록 하는 기술</p>
<blockquote>
<p>ex) 고속의 처리를 할 수 있는 중앙 서버에서
컴퓨터 자원들을 쪼개 번갈아 가며 사용자들의 요청을 처리해 주니,
사용자들은 응답에 대한 딜레이를 느끼지 못한다,
그래서 마치 자신이 서버를 독점하고 있다는 생각을 들게 할 수 있따.</p>
</blockquote>
<blockquote>
<p>references</p>
</blockquote>
<ol>
<li>혼공 - 운영체제:커널
<a href="https://hongong.hanbit.co.kr/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%9E%80-%EC%BB%A4%EB%84%90%EC%9D%98-%EA%B0%9C%EB%85%90-%EC%9D%91%EC%9A%A9-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%8B%A4%ED%96%89%EC%9D%84-%EC%9C%84%ED%95%9C/">https://hongong.hanbit.co.kr/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%9E%80-%EC%BB%A4%EB%84%90%EC%9D%98-%EA%B0%9C%EB%85%90-%EC%9D%91%EC%9A%A9-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%8B%A4%ED%96%89%EC%9D%84-%EC%9C%84%ED%95%9C/</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조] heap, 힙 with Python]]></title>
            <link>https://velog.io/@minj-j/heap-%ED%9E%99</link>
            <guid>https://velog.io/@minj-j/heap-%ED%9E%99</guid>
            <pubDate>Fri, 11 Aug 2023 16:05:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/minj-j/post/da3eceb5-91e2-4700-bb73-1a5b1b6ae23c/image.jpg" alt="힙터지는_현상"></p>
<h1 id="heap">Heap</h1>
<p>최대값이나 최솟값을 빠르게 찾아내기 위한 고안된 완전 이진트리를 기본으로 한 자료구조 이다.</p>
<p>최소 힙 : 자식 노드가 부모 노드보다 큰 완전 이진트리, 트리의 노드에는 가장 작은 값이 온다.</p>
<p>최대 힙 : 자식 노드가 부모 노드보다 작은 완전 이진트리, 트리의 노드에는 가장 큰 값이 온다.</p>
<h2 id="heap을-사용하면-좋은-점">Heap을 사용하면 좋은 점</h2>
<p>가장 크거나 가장 작은 값을 찾아내기에 좋다. 이진트리 가장 위 root 노드에 가장 크거나 작은 값이 저장되어 있기 때문이다.</p>
<p>그리고 heap을 정렬할 때도 자신 부모노드와 자신을 비교하여,
최대 힙일 땐 자신이 더 크면 부모와 자리를 바꾸고
최소 힙일 땐 자신이 더 작으면 부모와 자리를 바꾸면 된다.</p>
<p>이렇다 보니 수 전체와 자신을 비교할 필요가 없어 시간 복잡도가 줄어든다.</p>
<h2 id="시간복잡도">시간복잡도</h2>
<p>Heap 로직에 있어 가장 최악인 상황은 새로 추가된 노드가 Root 노드와까지 비교를 하게 되는 상황인데,
새로 들어오는 노드는 트리의 높이 만큼만 비교를 진행하면 된다.
그렇다면 알고리즘 수행에 필요한 단계수를 logN 만큼만 진행할 수 있으므로
Heap의 시간복잡도는** O(logN)**이다.</p>
<h2 id="파이썬에서-힙-사용하기">파이썬에서 힙 사용하기</h2>
<p>파이썬의 heapq는 모든 부모노드가 자식보다 작거나 같은 값을 갖는 이진트리이다.</p>
<pre><code class="language-python">import heapq</code></pre>
<p>로 heapq 모듈을 import 한다.</p>
<ul>
<li>heapq.heapify(x)
  : list x를 heap 구조로 변환시켜 준다.</li>
</ul>
<pre><code class="language-python">// heapfiy 직접 구현 해볼 것 -&gt; 링크 첨부</code></pre>
<p>🍒 <a href="https://velog.io/@minj-j/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Python%EC%9C%BC%EB%A1%9C-MaxHeap-%EA%B5%AC%ED%98%84%ED%95%B4%EB%B3%B4%EA%B8%B0">maxHeap에서의 Heapfiy 구현</a></p>
<ul>
<li>heapq.heappush(heap, item)
  : heap이라는 이름의 힙에 item을 push한다.
  push된 item은 이진트리의 가장 마지막 노드에 위치하게 된다.</li>
</ul>
<pre><code class="language-python">import heapq

heap = [3, 5, 1, 8, 4]

heapq.heappush(heap, 10)

print(heap) #[3, 5, 1, 8, 4, 10] heapify로 정렬을 하지 않아 가장 작은 값이 위로오지 않았다.</code></pre>
<ul>
<li>heapq.heapop(heap)
  : heap에서 가장 작은 항목을 pop한다.
  힙이 비어있으면 IndexError가 발생!<pre><code class="language-python">import heapq
</code></pre>
</li>
</ul>
<p>heap = [3, 5, 1, 8, 4]</p>
<p>heapq.heapify(heap) # [1, 4, 3, 8, 5]
heapq.heappush(heap, 10) # [1, 4, 3, 8, 5, 10]</p>
<p>print(heapq.heappop(heap)) # 1</p>
<p>print(heap) # [3, 4, 10, 8, 5] heappop 이후 가장 작은 값인 3이 힙의 root노드로 올라왔다.</p>
<pre><code>
- heapq.heappushpop(heap, item)
    : push랑 pop 섞어놓은 형태, item 푸시하고, heap에서 가장 작은 항목도 pop 해준다.

⭐_**아래 두 함수는 정렬 함수이다. 그러나 n값이 크면 sorted()로 정렬을 하는 것이 더 효율적이라고 한다. (python 공식 문서)**_⭐
- heapq.nlargest(n, iterable, key=None)
    : iterable에 정의된 데이터 집합에서 n개의 가장 큰 요소로 구성된 리스트를 반환 즉, 배열 내에서 가장 큰 순서대로 n개 반환해 준다는 의미이다.
    - iterable : member를 하나씩 차례로 반환 가능한 object
    예시로는 list, str, tuple이 있다.
```python
import heapq

list = [3, 5, 16, 89, 4, -10, -99, 1]

print(heapq.nlargest(5, list)) # [89, 16, 5, 4, 3]
</code></pre><p>key를 활용하여 람다식으로 응용해 볼 수 있다.</p>
<pre><code class="language-python">import heapq

data = [

 {&#39;goods&#39;: &#39;pizza&#39;, &#39;price&#39;:120},

 {&#39;goods&#39;: &#39;chicken&#39;, &#39;price&#39;:380},

 {&#39;goods&#39;: &#39;Tacco&#39;, &#39;price&#39;:987},

 {&#39;goods&#39;: &#39;pudding&#39;, &#39;price&#39;:402},
]

smallest = heapq.nlargest(3, data, key=lambda god: god[&#39;price&#39;])
print(smallest) 
# [{&#39;goods&#39;: &#39;Tacco&#39;, &#39;price&#39;: 987}, {&#39;goods&#39;: &#39;pudding&#39;, &#39;price&#39;: 402}, {&#39;goods&#39;: &#39;chicken&#39;, &#39;price&#39;: 380}]</code></pre>
<ul>
<li>heapq.nsmallest(n, iterable, key=None)
  : iterable에 정의된 데이터 집합에서 n개의 가장 작은 요소로 구성된 리스트를 반환 즉, 배열 내에서 가장 작은 순서대로 n개 반환해 준다는 의미이다.</li>
</ul>
<h2 id="최대-힙-만들기">최대 힙 만들기</h2>
<pre><code class="language-python">import heapq

        nums = [3, 4, 5, 2]
        heap =[]
        max_heap = []

        for s in nums:
            heapq.heappush(heap, (-s, s))

        print(heap) # [(-5, 5), (-3, 3), (-4, 4), (-2, 2)]

        while heap:
            max_heap.append(heapq.heappop(heap)[1])

        print(max_heap) # [5, 4, 3, 2]</code></pre>
<blockquote>
<p>📃 references</p>
</blockquote>
<ol>
<li><a href="https://docs.python.org/ko/3/library/heapq.html">https://docs.python.org/ko/3/library/heapq.html</a></li>
<li><a href="https://www.programiz.com/dsa/heap-data-structure">https://www.programiz.com/dsa/heap-data-structure</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[2. 동기와 비동기 그리고 form과 ajax]]></title>
            <link>https://velog.io/@minj-j/2.-%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0-ajax%EC%99%80-form</link>
            <guid>https://velog.io/@minj-j/2.-%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0-ajax%EC%99%80-form</guid>
            <pubDate>Tue, 08 Aug 2023 15:13:25 GMT</pubDate>
            <description><![CDATA[<p>지금 일하는 곳에서 Ajax form을 섞어서 쓰는데 쓰다보니까
무지성으로 되는거 그때그때 갖다 쓰는 느낌이라 알고서 사용하고 싶었다.
공부한거 토대로 리팩토링도 하고 오류도 잡아보고 싶어서..🫠
그래서 나한테 필요한 내용만 정리할거다 군데군데 빠진게 있어도 이해해주시길</p>
<h1 id="ajax-asynchronous-javascript-and-xml">AJAX (Asynchronous JavaScript and XML)</h1>
<p>서버와 클라이언트의 데이터 전송 및 처리를 비동기식으로 처리한다.
JS를 활용한 비동기적 통신 기법.
즉, 서버에서 응답을 받기도 전에 다른 작업을 처리한다.</p>
<p>또한 전체 웹 페이지를 다시 로딩하지 않고도, 웹 페이지의 일부분만을 갱신할 수 있어 시간이 절약된다!
ex) 수백줄로 구성된 웹페이지에서 바꾸고자 하는 데이터만 바꿀 수 있다.</p>
<h2 id="ajax의-기본-사용-형태">AJAX의 기본 사용 형태</h2>
<pre><code class="language-javascript">// with jQuery

$.ajax({
  method: &quot;POST&quot;, // HTTP 요청 방식
  url: &quot;/user/someFolder/some.do&quot;, // 클라이언트가 HTTP 요청을 보낼 서버의 URL 주소
  dataType: &quot;json&quot;, // AJax를 통해 호출한 페이지의 return 형식
  data: { name: &quot;John&quot;, location: &quot;Boston&quot; } // HTTP 요청과 함께 서버로 보낼 데이터
  error: function() { // 에러났을 때 처리함수
          console.log(&#39;connect fail&#39;);
  },
  success: function(data) { // 성공했을 때, 처리함수
        console.log(&quot;data : &quot; + data);
  }
});
</code></pre>
<p>장점 : </p>
<ol>
<li>페이지 리로드가 없어 Server 부담이 덜하고 속도도 빨라진다.</li>
<li>그래서 기존 페이지 내 데이터가 초기화 되지도 않는다.</li>
</ol>
<p>단점 : </p>
<ol>
<li>화면의 이동없이 Data를 송수신해 보안상 문제 있다.</li>
<li>Script 기반이라 디버깅이 어렵다</li>
</ol>
<blockquote>
<p>📃 Ajax reference</p>
</blockquote>
<ol>
<li><a href="http://www.tcpschool.com/ajax/ajax_intro_basic">http://www.tcpschool.com/ajax/ajax_intro_basic</a></li>
<li><a href="https://api.jquery.com/jquery.ajax/">https://api.jquery.com/jquery.ajax/</a></li>
<li><a href="https://inpa.tistory.com/entry/AJAX-%F0%9F%93%9A-%EC%84%9C%EB%B2%84-%EC%9A%94%EC%B2%AD-%EB%B0%8F-%EC%9D%91%EB%8B%B5-jQuery#.ajax">https://inpa.tistory.com/entry/AJAX-%F0%9F%93%9A-%EC%84%9C%EB%B2%84-%EC%9A%94%EC%B2%AD-%EB%B0%8F-%EC%9D%91%EB%8B%B5-jQuery#.ajax</a></li>
</ol>
<h1 id="form">Form</h1>
<p>서버와 클라이언트의 데이터 전송 및 처리를 동기식으로 처리한다.
그래서 데이터를 주고받을 때 웹 페이지 전체가 reload 된다.</p>
<p>제출 등의 버튼을 누른 후 페이지가 갱신되어야 하는 경우에 사용한다.</p>
<h2 id="form의-기본형태">Form의 기본형태</h2>
<pre><code class="language-html">&lt;form action=&quot;mywebsite.com&quot; method=&quot;POST&quot; name=&quot;webSite&quot;&gt;
    &lt;!--Input of any type and textareas goes in here--&gt;
&lt;/form&gt;</code></pre>
<p>action : <code>&lt;form&gt;</code> 태그에 입력된 내용을 처리하는 서버 프로그램의 URI를 지정하는 역할을 한다.
method : 사용자가 입력한 내용을 get, post 중 어떤 방식으로 넘길지를 정하는 역할</p>
<ul>
<li>이때, post방식은 입력된 내용의 크기에 제한을 받지 않고 입력한 내용이 노출되지 않아 보안이 요구되는 기능에 사용된다.
name : 한 문서에 여러개의 <code>&lt;form&gt;</code>이 있을 때, form을 구분하기 위해 사용된다.</li>
</ul>
<p>장점 : </p>
<ol>
<li>직관적임</li>
</ol>
<p>단점:</p>
<ol>
<li>전체 페이지를 reload 하기 때문에 서버의 부하가 크고</li>
<li>페이지를 새로 읽어와야 해서 시간도 오래걸린다.</li>
</ol>
<blockquote>
<p>📃 Form reference</p>
</blockquote>
<ol>
<li><a href="https://www.freecodecamp.org/korean/news/html-form-input-type-and-submit-button-example/">https://www.freecodecamp.org/korean/news/html-form-input-type-and-submit-button-example/</a></li>
</ol>
<p>정리해보니 좋다 나쁘다로 나뉘어 지는게 아니라
상황에 따라 적절한 요소를 골라써야 하는구나 싶었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[???: 현 시간부로 대답은 모두 ACK으로 통일한다]]></title>
            <link>https://velog.io/@minj-j/%EB%8C%80%EB%8B%B5%EC%9D%80-ACK%EC%9C%BC%EB%A1%9C-%ED%95%A9%EB%8B%88%EB%8B%A4</link>
            <guid>https://velog.io/@minj-j/%EB%8C%80%EB%8B%B5%EC%9D%80-ACK%EC%9C%BC%EB%A1%9C-%ED%95%A9%EB%8B%88%EB%8B%A4</guid>
            <pubDate>Tue, 08 Aug 2023 14:25:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/minj-j/post/2f12cb38-c11b-4957-a7d7-bc559f5c8599/image.png" alt=""></p>
<p>의 ACK가 무엇이죠?
모르는 부끄러움 보다 모르면서 아무말하는게 더 부끄럽다.</p>
<h1 id="ack">ACK</h1>
<p>TCP 메시지유형 중 응답 타입이다</p>
<blockquote>
<p><a href="https://www.guru99.com/tcp-3-way-handshake.html">https://www.guru99.com/tcp-3-way-handshake.html</a></p>
</blockquote>
<p>해당 레퍼런스에서 TCP 메시지 유형을 볼 수 있는데 이곳에서
🆎 ACK(Acknowledgment) : Helps to confirm to the other side that it has received the SYN.
🆕 ACK : 다른 쪽에서 SYN을 수신했음을 확인하는 데 도움이 됩니다.
이라고 나와있다.</p>
<p>한마디로 SYN을 수신했다고 보내주는 메시지인 것이다.</p>
<p>그럼 SYN은 무엇인가?</p>
<h1 id="syn">SYN</h1>
<p>TCP에서 세션을 성립할 때 가장 먼저 보내는 패킷, 시퀀스 번호를 임의적으로 설정해 준다.</p>
<p>🆎 SYN(synchronize sequence numbers) : Used to initiate and establish a connection. It also helps you to synchronize sequence numbers between devices.
🆕 SYN : 연결을 시작하고 설정하는 데 사용되며, 장치 간에 시퀀스 번호를 동기화하는 데도 도움이 됩니다.</p>
<p>그러면 TCP는?</p>
<h1 id="tcp">TCP</h1>
<p>TCP(Transmission Control Protocol) : 서버와 클라이언트간에 데이타를 신뢰성있게 전달하기 위해 만들어진 프로토콜</p>
<p>데이터는 네트워크를 통해 전달되는 과정에서 손실되거나 순서가 뒤바뀔 수가 있는데 TCP는 이 손실을 찾아내어 이를 교정하고 순서를 순서대로 재조합 할 수 있도록 해준다.</p>
<p>연결지향 프로토콜</p>
<blockquote>
<p>TCP/IP
<a href="https://www.joinc.co.kr/w/Site/Network_Programing/Documents/IntroTCPIP">https://www.joinc.co.kr/w/Site/Network_Programing/Documents/IntroTCPIP</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[1. 동기와 비동기]]></title>
            <link>https://velog.io/@minj-j/1.-%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0</link>
            <guid>https://velog.io/@minj-j/1.-%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0</guid>
            <pubDate>Tue, 08 Aug 2023 14:02:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/minj-j/post/551b79d0-cc71-463f-a60c-f2495a5cf941/image.jpg" alt=""></p>
<p>웃기지만 아직도 헷갈린다.
그럼 지대로 모른다는 소리겠지?</p>
<p>대충이라도 정리해보려고 한다.</p>
<h1 id="1-동기-synchronous">1. 동기 Synchronous</h1>
<p>동기는
어떤 요청에 대한 결과가 동시에 일어난다는 것이다.
그래서 응답을 하는 도중 다른 응답을 받을 수 없다.</p>
<p>요청에 대한 결과가 동시에 일어나려면 해당 요청만 처리해야 겠지?
그래서 해당 요청에 대한 응답이 끝날때까지 다른 요청에 대한 결과를 반환하지 못한다.</p>
<p>한번에 한 요청만 처리</p>
<p>이때 동기적인 작업으로 인해 이후의 작업이 막히게 된 것을 Blocking이라고 한다.</p>
<p>안 잊어버릴라구 많이 돌아다니는 예시까지 주워왔다.</p>
<blockquote>
<p>🍨 카페에서
커피를 주문했을 때,
자리에서 안기다리고,
커피가 나올때까지 카운터에서 기다림,
다른 손님은 기다리는 나 때문에 주문을 할 수가 없음</p>
</blockquote>
<p>💁‍♀️
장점 : 직관적
단점 : 근데 한 요청에 대한 결과가 끝날때 까지 다른 일을 못함</p>
<h1 id="2-비동기-asynchronous">2. 비동기 Asynchronous</h1>
<p>비동기는
응답을 하는 도중 다른 응답을 받을 수 있다.</p>
<p>그래서 해당 요청을 받는 중 다른 요청이 들어오면 그 요청도 처리하러 간다.
그래서 해당 요청에 대한 결과가 바로 일어나지 않는다.</p>
<p>이말은 즉, 여러개의 요청을 동시에 처리한다는 것이다.</p>
<p>하나의 작업이 진행되는 도중 다른 작업에 대한 처리가 막히지 않으니
이는 non-blocking 이라고 한다.</p>
<blockquote>
<p>🍨 카페에서
커피를 주문했을 때,
점원이 진동벨 주고 자리에서 기다려 주세요 함,
나는 자리에 가고 점원은 다른 손님의 주문을 받음</p>
</blockquote>
<p>💁‍♀️
장점 : 효율적
단점 : 직관적이지 못해 복잡함</p>
<blockquote>
<p>📃reference
<a href="https://www.freecodecamp.org/news/node-js-what-when-where-why-how-ab8424886e2/">https://www.freecodecamp.org/news/node-js-what-when-where-why-how-ab8424886e2/</a></p>
</blockquote>
<h1 id="🤔서버를-비동기식으로-구성하면-좋은-점이-뭘까요">🤔서버를 비동기식으로 구성하면 좋은 점이 뭘까요?</h1>
<p>장: 하나의 요청을 처리함과 동시에 다른 요청도 처리할 수 있다.
단: 설계가 복잡하며 데이터의 정합성이 떨어질 수 있다.</p>
<blockquote>
<p>📃비동기 모니터링
<a href="https://jennifersoft.com/ko/blog/tech/asynchronous-monitoring">https://jennifersoft.com/ko/blog/tech/asynchronous-monitoring</a></p>
</blockquote>
<p>간단하게 여기까지만 정리해 보긴 했는데
동기 비동기를 공부하면서 Thread, Promise등 비동기적 처리를 위해
봐야할 것들이 많음을 알게되었다. 이것도 차차 정리해보고자 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스/Python] 최고의 집합]]></title>
            <link>https://velog.io/@minj-j/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4Python-%EC%B5%9C%EA%B3%A0%EC%9D%98-%EC%A7%91%ED%95%A9</link>
            <guid>https://velog.io/@minj-j/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4Python-%EC%B5%9C%EA%B3%A0%EC%9D%98-%EC%A7%91%ED%95%A9</guid>
            <pubDate>Mon, 07 Aug 2023 13:55:06 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/minj-j/post/2af0926a-4698-40fc-a3d3-2988196b1539/image.png" alt=""></p>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/12938">프로그래머스 : 최고의 집합 바로가기</a></p>
<h2 id="🐰풀이-과정">🐰풀이 과정</h2>
<p>개인적으로 느낀게 많아서 후닥닥 적어본다.</p>
<p>이것을 풀고자 했을 때 든 생각은 우선 주어진 S가 될 수 있는
조합을 찾아야겠다! 라는 생각에
python의 Combination 모듈을 사용하려 했다.
근데 Combination은 배열이 주어졌을 때만 사용이 가능하였다.</p>
<p>그래서 이런 생각이 들었다. </p>
<h1 id="s의-조합을-찾는-방법을-모르겠다">S의 조합을 찾는 방법을 모르겠다.</h1>
<p>30분 머리를 굴려봐도 비효율적인 방법만 나와가지고
다른 사람의 풀이를 참고하기로 하였다.</p>
<h2 id="🐰풀이-결과">🐰풀이 결과</h2>
<pre><code class="language-python">def solution(n, s) :
    answer = []
    if n &gt; s: # 이런 경우는 -1을 출력하라 했으므로 예외처리
        answer.append(-1)
        return answer

    # divmod() 함수 s // n의 몫과 나머지를 모두 구해주는 함수
    quo, rem = divmod(s, n)

    answer = [quo] * n # n만큼 몫을 배열에 넣어주고
    for i in range(rem): # 나머지만큼 for문을 돌려
        answer[i] += 1 # 몫이 들어있는 배열에 1을 더해줘 나간다.
    return sorted(answer) # 그럼 가장 큰 곱이 나올 집합이 나오게 된다.
print(solution(2, 8))</code></pre>
<p>그렇게 divmod() 함수를 사용하여 한 풀이로 해당 문제를 풀 수 있었다.</p>
<p>나는 조합에 집착을 하고 있었는데, 이분은 큰 곱을 만들려면 큰 수끼리 곱을 하면 되니까 어떻게 큰 수들을 만들지 궁리를 하셨던 것이었다.</p>
<p>나는 이 풀이를 보고</p>
<p>단순히 문제에서 요구하는 조건을 모두 구현하는 것이 아니라
어떻게 짧고 효율적인 방법으로 답을 도출할 것인지를
생각해야 한다는 것을</p>
<p>조합을 찾을 필요가 없었다 우리가 필요한 건
S가 되는 집합 들의 곱 중 가장 큰 곱을 찾는 것,
그러니 집합내의 숫자들이 가장 큰 집합을 찾아내는 
코드를 작성해야 한다.</p>
<p>는 것을 깨달았다.</p>
<p>어려워 머리굴리는게 너무 어려워😬</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스/Python] 정수삼각형]]></title>
            <link>https://velog.io/@minj-j/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4Python-%EC%A0%95%EC%88%98%EC%82%BC%EA%B0%81%ED%98%95</link>
            <guid>https://velog.io/@minj-j/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4Python-%EC%A0%95%EC%88%98%EC%82%BC%EA%B0%81%ED%98%95</guid>
            <pubDate>Mon, 07 Aug 2023 13:43:30 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/minj-j/post/55ebddaf-39e9-41b8-a172-f90e84535379/image.png" alt=""></p>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/43105">프로그래머스 : 정수삼각형 문제 바로가기</a></p>
<h2 id="🐰풀이-결과">🐰풀이 결과</h2>
<pre><code class="language-python">def solution(triangle):

    for i in range(1, len(triangle)):
        for j in range(i+1):
            if j==0: # 숫자가 가장 왼쪽에 있을 때
                triangle[i][j] += triangle[i-1][j]
            elif j==i: # 숫자가 가장 오른쪽에 있을 때
                triangle[i][j] += triangle[i-1][-1]
            else: # 가운데 부분에 있을 때
                triangle[i][j] += max(triangle[i-1][j-1], triangle[i-1][j])

    return max(triangle[-1])</code></pre>
<h2 id="🐰풀이-과정">🐰풀이 과정</h2>
<p>Dynamic Programming 동적 계획법 문제였다.
DP문제는 상향식 풀이법? 하향식 풀이법? 그런 것이 있는데
모르겠다. 일단 풀이 흐름을 이해하는 것이 먼저였기에..</p>
<p>[[7], [3, 8], [8, 1, 0], [2, 7, 4, 4], [4, 5, 2, 6, 5]]<br>이 배열들 각각의 위치에 대각선 방향에 있는 숫자들을 더한 값을 저장해 놓을까 하는 생각을 하였다. 구현은 못했지만 ^_^</p>
<p>근데 풀이법에 거의 접근은 하였다.</p>
<p>아래 사진을 봐보자
<img src="https://velog.velcdn.com/images/minj-j/post/0e17cdc0-5e62-4a14-8b3a-e12947fd4235/image.png" alt=""></p>
<p>나의 풀이는 아래에서 위로 올라가며 계산식을 triangle 이라는 배열에 
저장할 것이다.</p>
<p>정수 삼각형은 한 자리에서 왼/오 대각선으로 밖에 이동하지 못한다.
그렇다면 이때, 삼각형의 가장자리 빨간 동그라미 친구들은 선택지가 하나 밖에 없다. 위로만 갈 수 있다.</p>
<p>그래서 </p>
<ol>
<li>숫자가 가장 왼쪽에 있을 때</li>
<li>숫자가 가장 오른쪽에 있을 때의 경우를 찾아 </li>
</ol>
<p>그들은 자신의 바로 위 대각선의 있는 숫자들과 더해질 수 있도록 하면 된다.</p>
<p>파란 동그라미 친구들도 봐보자,
이들은 갈수있는 경우가 두가지 이다 왼쪽으로 가거나 오른쪽으로,
우리는 거쳐간 숫자가 최대가 되도록 하는 수를 return해야 한다.
그러면 큰 수가 있는 대각선으로 덧셈을 해나가도록 해야 한다.</p>
<p>그러므로 내 앞에 있는 두개의 숫자 중 가장 큰 숫자로 갈 수 있도록 Max()를 걸어두면 된다.
=&gt; triangle[i][j] += max(triangle[i-1][j-1], triangle[i-1][j])</p>
<p>이렇게 덧셈이 끝난 숫자들은 triangle 배열의 각 자리에 들어가게 된다.
가장 마지막에는 모든 덧셈이 끝난 가장 최대의 수가 저장되어 있다.</p>
<p>그러므로 triangel[-1]을 리턴하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클라우드 첫걸음, NHN Cloud로 시작하기 - Part2]]></title>
            <link>https://velog.io/@minj-j/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EC%B2%AB%EA%B1%B8%EC%9D%8C-NHN-Cloud%EB%A1%9C-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-Part2</link>
            <guid>https://velog.io/@minj-j/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EC%B2%AB%EA%B1%B8%EC%9D%8C-NHN-Cloud%EB%A1%9C-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-Part2</guid>
            <pubDate>Mon, 07 Aug 2023 13:09:19 GMT</pubDate>
            <description><![CDATA[<p>웹 사이트 구축 전, 네트워크를 구축하는 리전이 어디인지를 확인한다.
앞으로 진행할 실습에서는 평촌 리전에서 진행한다.</p>
<h3 id="lab1-소규모-웹-사이트-구축하기-1---네트워크-환경-구축">LAB1. 소규모 웹 사이트 구축하기 #1 - 네트워크 환경 구축</h3>
<hr>
<p><img src="https://velog.velcdn.com/images/minj-j/post/ee928408-9ac7-40b8-8a22-e0b7b6d34bd1/image.PNG" alt=""></p>
<p><strong>위의 사진과 같은 시나리오로 네트워크를 구축하기</strong></p>
<ol>
<li>인스턴스 서비스를 선택하면서 자동으로 생성된 default VPC를 Management VPC로 바꾸고 Service VPC를 하나 더 만든다.</li>
<li>public network로 service_vpc용 인터넷 게이트웨이를 만들어 준다. default VPC는 인터넷 게이트웨이가 자동 할당되어 있어 별도 작업은 필요하지 않다.</li>
<li>만든 service_vpc용 인터넷 게이트웨이를 service_vpc와 라우팅 연결한다.</li>
<li>default 서브넷을 Management용 서브넷으로 이름을 변경하고 Service용 서브넷도 2개 생성한다.</li>
</ol>
<p>여기까지 하면 위와 같은 시나리오로 네트워크를 구축할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/minj-j/post/a789419d-9139-4ec4-bb3b-512804fa841d/image.PNG" alt=""></p>
<p>다음은 위의 사진과 같이 서브넷 마다 인스턴스를 설치하고 각 VPC를 피어링을 통해 통신시키고자 한다.</p>
<p><strong>인스턴스 설치 후 피어링으로 VPC간 통신시키기</strong></p>
<ol>
<li>mgmt-server라는 이름의 인스턴스를 생성한다. 보안그룹에는 내 IP로 22번 포트에서 들어올 수 있도록 허용하는 규칙을 추가해 준다.</li>
<li>web1도 같은 방식으로 만들어 준다.</li>
</ol>
<p><strong>DB 서버 만들기</strong></p>
<ol>
<li>인스턴스 만들기에서 공용이미지 &gt; DBMS &gt; MariaDB를 설정한 후 가장 위에 있는 이미지를 선택한다.</li>
<li>가용성 영역은 KR-a로 선택한다.</li>
<li>Private_subnet에 만들 예정이기 때문에 해당 서브넷 네트워크를 선택한다.</li>
<li>db용 보안그룹을 추가해 준 뒤 인스턴스를 생성한다.</li>
</ol>
<p>mgmt 서버에서 web1과 db 서버에 접속하기 위해서는 키페어를 mgmt 서버에 올려야 한다.
그리고 ssh -i [키페어] centos@[각 서버 IP 주소] 로 접속하는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/minj-j/post/de4663ca-fd03-4ecb-8a31-42b5c00e23b6/image.PNG" alt=""></p>
<p>전송한 키는 chmod로 관리자만 접근할 수 있게 권한을 변경해야 한다.</p>
<ol start="5">
<li><p>mgmt 서버와 service 서버가 연결될 수 있는 피어링 게이트웨이를 생성한다.
<img src="https://velog.velcdn.com/images/minj-j/post/d155d053-31c8-4169-8cf2-1f48763c11dc/image.PNG" alt=""></p>
</li>
<li><p>각 VPC의 라우팅 테이블에 피어링 게이트웨이 정보를 추가한다.</p>
</li>
</ol>
<p>[ mgmtVPC 라우팅 정보]
<img src="https://velog.velcdn.com/images/minj-j/post/f20d900e-4266-41f7-9dff-e880c1ddd1c0/image.PNG" alt=""></p>
<p>[ service-VPC 라우팅 정보]
<img src="https://velog.velcdn.com/images/minj-j/post/c67128b2-7de1-4e3e-8978-081bd44f4a84/image.PNG" alt=""></p>
<p>이렇게 구성하면 mgmt 서버에서 ssh 명령으로 web1과 db서버에 접근해보자</p>
<p>먼저 각 보안그룹에 mgmt 서버의 IP 주소로 22번 포트에서 들어올 수 있도록 하는 규칙을 추가해야 한다.</p>
<p><img src="https://velog.velcdn.com/images/minj-j/post/c1888b4c-8ae7-4b64-90b5-f498bc3d62fb/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/minj-j/post/0dfe1fbe-67b5-4e65-91eb-bd2ff8b186b3/image.PNG" alt=""></p>
<p>이렇게 보안 그룹을 수정하면
<img src="https://velog.velcdn.com/images/minj-j/post/dabfc9ce-549e-4bc7-ae47-4423df8a6f32/image.PNG" alt=""></p>
<p>다음과 같이 mgmt 서버에서 web1과 mydb에 접속할 수 있게 된다.</p>
<p><strong>web1에서 DB서버로 접속하기</strong></p>
<p>3306 포트로 web1에서 db서버로 접속을 할 것이다.</p>
<ol>
<li>보안그룹에 3306 포트에서 web1의 IP로 db서버에 접근할 수 있도록 규칙을 추가해 준다.</li>
<li>myssql -h [db서버주소] 아이디 -p 명령으로 웹 서버에서 db 서버로 접속한다.</li>
</ol>
<p><strong>php 웹페이지에 자신의 DB 내로 데이터가 저장되도록 하기</strong>
1.web서버를 만들때 미리 돌린 사용자 스크립트로 만들어진 php파일을 찾는다 -&gt; /var/www/html/process_create.php 에 있음
2. vi로 편집기를 열어 DB가 나의 db서버 IP로 연결될 수 있도록 db IP 정보를 수정해 준다.</p>
<p>이미지 생성하기
이미지를 만들 때는 이미지를 만들 인스턴스를 중지하고 진행해야 한다.</p>
<p><strong>생성한 이미지로 KR-b 가용성 영역에 웹서버 하나 더 만들기</strong>
내가 생성한 이미지로 KR-b 영역에 똑같은 웹서버를 하나 더 만든다.
이렇게 하면 KR-a 영역에서 장애가 생겨도 KR-b 영역으로 옮겨가 안정적으로 서비스를 제공할 수 있게 된다.</p>
<p><strong>Load Balancer 생성하기</strong>
로드 밸런서 : 대규모 트래픽을 분산시켜주는 기능</p>
<p>로드 밸런서를 사용하는 이유 :
상태 확인 주기 순서대로 트래픽을 점검하여 해당 서버의 장애와 비장애 여부를 판단한다.</p>
<p>LB 동작 프로세스를 알아야 트러블 슈팅하기에 좋다고 한다.</p>
<p>리스너 : 로드 밸런서로 유입되어 처리될 트래픽은 리스너에서 정의한다.
예를들어 tcp 80포트만 처리하도록 설정시 80번 포트만 처리될 수 있다.</p>
<ol>
<li><p>로드 밸런서를 어느 곳에 설치할지를 정의한다.
예제에서는 service_VPC의 public_server(웹서버)와 연결될 수 있도록 설치하였다.</p>
</li>
<li><p>리스너 조건을 입력해 준다.
tcp 80번 포트의 트래픽만 상태 확인을 진행하고 30초씩 확인을 한다.
최대 응답 대기시간은 5초이고 최대 응답 재시도 횟수는 2번으로 하였다. 2번이 넘어가면 장애로 판단 후 더 이상 상태를 확인하지 않는다.</p>
</li>
<li><p>해당 로드벨런서에 플로팅 IP를 할당한다.</p>
</li>
<li><p>로드밸런서와 웹 서버들이 서로 연결 될 수 있도록 로드밸런서의 사설 ip를 web-sg 보안 그룹에 추가해 준다.</p>
</li>
<li><p>해당 로드밸런서를 KR-b 영역에 있는 웹서버와도 연결시켜준다.</p>
</li>
<li><p>로드 밸런서의 플로팅 IP로 접속하면 웹페이지가 뜬다.
해당 웹페이지에 데이터를 입력하면 연결된 db로 데이터가 저장되는 것을 볼 수 있다.</p>
</li>
</ol>
<h3 id="시스템-모니터링">시스템 모니터링</h3>
<hr>
<p>사용자 그룹을만들고 그 안의 알림 그룹을 통해 시스템에 생기는 이슈들에 대한 알림을 받을 수 있다.
ex. CPU의 임계값이 특정 범위를 특정 시간 동안 넘어서면 문자나 이메일로 알림을 보내라</p>
<h3 id="scale-in--out">Scale-in &amp; Out</h3>
<hr>
<p>Auto Scale : 인스턴스의 부하 또는 장애 등과 같은 상황을 대비해 지속적으로 모니터링하여
인스턴스를 확장하거나 축소할 수 있는 클라우드 핵심 기술</p>
<p>Scale Up은 서버의 크기 자체를 늘리는 것 ex. cpu1 2GB 메모리를 cpu8. 16GB 메모리로 늘리는 것
Scale Out은 서버의 규모를 늘리는 것 ex. 1대이던 서버를 20대로 늘린다.</p>
<p><strong>Auto Scaling Group 만들기</strong>
스케일링을 할 인스턴스 템플릿을 정한 후
특정 임계치에 도달하면 추가될 인스턴스 개수를 정해준다.
그럼 임계치에 다다른 인스턴스는 scale out을 통해 서버가 증설되고
임계치에서 멀어지면 증설된 인스턴스는 오래사용된 것 순으로 사라진다.</p>
<p>스케일링은 각 인스턴스 사용량의 평균치를 계산하여 인스턴스 개수를 조절한다.</p>
<p><strong>Stress로 부하 테스트</strong>
Stress 명령으로 강제로 부하를 주면
서버가 증설되어 웹페이지 새로고침시 다양한 경로의 IP로 웹페이지에 접근할 수 있는 것을 볼 수 있게된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/Python]백준 4637번 셀프넘버]]></title>
            <link>https://velog.io/@minj-j/%EC%BD%94%ED%85%8CPython%EB%B0%B1%EC%A4%80-4637%EB%B2%88-%EC%85%80%ED%94%84%EB%84%98%EB%B2%84</link>
            <guid>https://velog.io/@minj-j/%EC%BD%94%ED%85%8CPython%EB%B0%B1%EC%A4%80-4637%EB%B2%88-%EC%85%80%ED%94%84%EB%84%98%EB%B2%84</guid>
            <pubDate>Mon, 07 Aug 2023 13:03:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/minj-j/post/724f1bfc-15af-4a6a-ad19-aa25545859a9/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/4673">백준 4637번 : 셀프넘버</a></p>
<h2 id="🐰-풀이-과정">🐰 풀이 과정</h2>
<p>우선 첫 번째 접근은 주어진 양의 정수 n을 10으로 나누고 나누고 하여
어떻게든 숫자를 쪼개려 하였다. 
ex) n = 39 이면 n + (n/10) + (n%10) ..</p>
<p>하지만 이렇게 하면 위의 셈법이 적용되지 않는 숫자들이 너무 많았다.</p>
<p>심지어 첫 번째 풀이에서는 1~10000까지의 숫자를 배열에 저장해 두고
배열 내에 있는 숫자들을 하나씩 빼와서 계산하려 하였다.</p>
<p>그러다 찾은 풀이는 1<del>10000까지의 숫자들을 집합에 넣어두고
셀프 넘버인 숫자들을 구한 후 셀프 넘버들을 1</del>10000까지의 숫자들의 집합에서 빼는 것이었다.</p>
<p>set() 함수는 집합의 개념이라 합, 차, 곱이 가능하다는 것이 특징이다.</p>
<p>그리고 셀프 넘버가 아닌 숫자들은 숫자를 문자로 치환하여-&gt; str(숫자)
숫자들을 하나하나 떼어내면 셀프 넘버가 아닌 수를 구할 수 있는 식이 나왔다.
각 자리의 숫자합의 결과들은 셀프 넘버 아님으로 not_self_num 집합에 넣어준다.</p>
<h2 id="🐰-풀이-결과">🐰 풀이 결과</h2>
<pre><code class="language-python">number_set = set(range(1, 10001)) # 문제에서 요구하는 숫자 범위

not_self_num = set() # 셀프 넘버가 아닌 수들을 저장할 집합

for i in range(1, 10001): # 1~10000까지 숫자들을 모두 돌며 셀프넘버가 아닌 수를 구한다.
    for j in str(i): # 숫자를 문자로 치환해 하나하나 떼어낸 후
        i += int(j) # 다시 숫자로 치환해 더한다.
    not_self_num.add(i) # 결과 값은 셀프 넘버가 아니므로 not_self_num에 집어넣는다.

self_num = sorted(number_set - not_self_num) # 집합 함수는 차 집합이 가능하므로 전체 넘버set에서 셀프넘버가 아닌 집합을 빼준다.

for i in self_num:
    print(i)</code></pre>
<h2 id="🐰-알게-된-것">🐰 알게 된 것</h2>
<p>set() 함수</p>
]]></description>
        </item>
    </channel>
</rss>